Files
weewx/setup.py
Bill Richter 93436a927c once again try to update my fork (#2)
* Got test suites working again.

* Updated TODO

* indicate specific firmware for cc3000

* clarify rainwise firmware

* Further refinement

- max and maxtime now updated
- reworked the progress function, now a method in the class

Have left __main__ code in that has been used for testing windSpeed
recalculation fix

* indicate when calibrations are ignored

* Now emits the barometer trend in LOOP packets as field 'trendIcon'

Vantage only.

* Updated TODO guide, reflecting this morning's phone call.

* Presses on, despite database error

* Simplified patching by moving metadata code to DaySummaryManager

* Got rid of _getVersion()

Can now get it from _read_metadata

* Remove interval weighting fix from weewx startup

Refer TODO.txt

* Update TODO.txt

* added write timeout to ultimeter driver

* better logging when cc3000 loses contact with sensors

* document some of the channel, sensor, and logger specifics for the wmr100/wmr200 hardware

* Removed the p word, patch.py is now database.py, rejigged wee_database as per skype and followup emails

- progress function for fixes included as a method in base class that
can be overridden
- much changing of logging to give consistent results/output
- believe I retained Tom's recent changes to patch.py (commit 4acf752)

* Picks daily summary weights on the basis of database version

* Rewrote the backfill routine (again)

* wee_database now uses new version of backfill_day_summary

* Fixed problem that prevented cold startup

* Revised to reflect latest wee_database incantation

* Modified weighting fix

Should not mess with lessUpdate
Delete lastWeightPatch after successful patch

* Check to make sure the daily summaries have not been partially updated.

* Revised to reflect latest wee_database incantation

* Revised wee_database and interval weighting paras, added windSpeed recalc para

* Removed vacuum

* Updated what has been done and committed

* Better diagnostics with partial update of the daily summaries.

* MySQL now uses transaction isolation level READ COMMITTED

* Add .config (#204)

* Changed semantics of "$last_xxx" tags.

* Template test updates including fixing issue #201 (#205)

* Add .config

* Standardise test skin for index.html.tml to remove "%x %X" locale dependent formatting. Note: Used 24 hour time as AM/PM can also be locale dependent.

Also include fixes for line formatting in some other test files and expected results.

* sysctlbyname is not available on every platform, so catch AttributeError too, otherwise cheetah fails with a name error

* Got rid of tabs

* update usb mode info for acurite models

* Removed intervalgenRoundTS and archiveDaysAgoSpan.

* Simplified tags. Got template test working again.

* Somehow, style "indent" got lost

* Documented new "$ago" tags.

* Documented $ago options, as well as .start and .end

* Update changes doc

* Stupid typo

* use markdown instead of html for README

* indenting seems to confuse markdown's handling of urls

* Left over $last_day in $spans example (#206)

* Add .config

* Standardise test skin for index.html.tml to remove "%x %X" locale dependent formatting. Note: Used 24 hour time as AM/PM can also be locale dependent.

Also include fixes for line formatting in some other test files and expected results.

* Left over $last_day in $spans example.

* a user-specified sensor_map will update, not replace, the default sensor_map

* Updated the upgrade guide.

* ensure that weewx-multi works on deb and rpm as well as setup.py

* document the sensor mapping changes

* Added comprehensive example to customizing guide.

* Updated TODO

* Got the weighting update to work on MySQL

* added crude caching of pressure in wmr300

* Fixed typo

* Fixed little errors. Consistently use "tag", instead of "dot code."

* no altimeter, just pressure and barometer

* Fixed little HTML problems.

* Reformatted, in anticipation of a refactoring of some sections.

* Fixed location of 'Version'

So it works with automatic replacement of 'Version'

* initial experiment with different fonts

* override jquery-ui hijacking of toc font family

* bring header highlighting to h2 to correlate with toc.  reduce post-header margins.

* fix some table header cruft.  prevent indent sections from overflowing right margin.  let the table cells breath.

* fix broken tty formatting

* Checkpoint

Work in progress.

* Refined examples of creating new units and groups

* Polishing. Or, maybe fiddling?

* minor css fixes.  rearrange troubleshooting sections about pressure.

* minor cleanup to readme

* Fixed test suites

Add MySQL back to template tests.

* Reworked the iteration examples.

* Corrected and clarified the units used in the "electricity" example.

* remove write_timeout since naming is inconsistent between pyserial versions and there is no backward compatibility

* remove write_timeout from ultimeter

* Minor changes to users guide

* increase body size to 100%.  background for code.  weeWX in titles.  true bold for monospace.  prep for direct font comparisons.

* Clarified the role of encoding

* update utilities guide with suggested wee_database descriptions and args

* more compaction

* increase margins on html examples.  use droid serif for html examples.

* Clarified a few things

* decode weewx into weeWX

* include transaction limit defaults

* eliminate transaction-limit

* weeWX fixes in install pages.  more fixes to utilities.

* missed a few code spans

* fix version label alignment

* use only major.minor for docs

* Fix error where import fields that are None can cause Source.mapRawData() to crash in some cases

* Updated TODO and NEW_FEATURES

* There will be no daykeys if the daily summaries have been dropped.

* Restructure usage string, hard code transaction days

* dry-run goes with fix-strings, not check-strings

* Log daily summary version

* No need to check for weewx.debug

* include examples in manifest

* added examples and extensions to data_files

* do not install sample extensions

* Can now specify date field separator for Cumulus imports, weewx -> weeWX

* Clarified option strings

* Rudimentary test of selective daily summary rebuild

* No longer allows selective rebuild of the daily summaries

if the summaries are not complete

* Hardwired UTF-8 encoding, but with a warning comment.

* Hardwired UTF-8 encoding, but with a warning comment.

* Documented Cumulus import separator config option

* Added comments about Tools.

* Changed to execute in user environment

* Ported to PyMySQL as an alternative to python-mysqldb

See https://github.com/PyMySQL/PyMySQL for a description of PyMySQL

* Recognize additional MySQL "Can't connect" error

* Fixed error in test suites

Subsequent tests depended on ordering of a dictionary.

* pymysql seems to have problems connecting via file socket

unless it is told explicitly about it.

* Workaround for pypy compiler

* Defaults now support MySQLdb over pymysql

* Fixed bug in record augmentation.

The augmentation was happening without giving StdConvert a chance to do
its thing.

* More clear msg when encountering an ImportError

* Clarified the relationship between archive period and report_timing option, aded note regarding primacy of the report cycle

* Reverted back to MySQLdb only version.

* Changed config option names but never changed the code!

* One transaction for updating daily high/lows and archive record

Formerly, these were done in two transactions.

* v3.7.0a2

* Adjustable value for how long to wait after a bad uploader login.

Option retry_login. Fixes issue #212.

* Fixed Cumulus import rain field issue

wee_import will try to use field 26(AA) - midnight reset daily rainfall
but if not available due it will revert to field 9(J) or 11(L)

* Switched back to __str__ when extracting string out of template.

.respond() doesn't seem to encode Unicode characters properly

* Fix errors in wee_import WU step-by-step, remove Cumulus version caveat on rain

* Now uses dedicated test users 'weewx1' and 'weewx2'

* Formal check of the various MySQLdb exceptions.

* Added sqlite3 exceptions.

* Reworked check_strings() output (#213)

Reworked check_strings() screen and syslog output:
- now gives progress ala --rebuild-daily
- syslog is silent for --check-strings and --fix-strings with --dry-run
- left 'Preparing' (rather than 'Starting') but added 'this may take a
while' as there is a significant delay in dbmanager.genBatchRows()
initialising at line 619 (well there was for 400k records)

* reduce debug log spewage in wmr300 driver

* Finished formal test of errors

* First cut at V3.7 exception hierarchy

* Ported the weedb sqlite driver to the new exception hierarchy.

* Ported MySQLdb to the new database exception hierarchy.

* windSpeed fix now gracefully handles no windSpeed summary table, tweaked --update output/logging

* Now picks up absence of windSpeed daily summary

* The weedb Connection object can now be used in a "with" clause.

* The weedb Cursor object can now be used in a "with" clause.

* V3.7.0a3

* more code removal

* code formatting only

* use apt instructions for debian installs

* Reworked --wee-database section of Utilities Guide to reflect current wee-database operation

- revised usage
- reword --rebuild-daily
- reword --check
- reword --update

* More details on upgrading

* Moved start time to just before applying the patch

* Accumulator is now initialized with override values from weewx.conf

* Added sentences about wee_import/interval and weight patching multiple dbs

* remove extensions from rpm and deb packages

* v3.7.0b1

* Cleaned up some HTML warnings.

* must do a try loop at the read level so we can skip the no data 'errors' and return empty buffer so that a subsequent write will get the station to talk again

* Slightly more robust mechanism for decoding last time a file was FTP'd.

* adjust wording of weighting description

* added examples

* simplify

* fixed typo

* fixed typo

* read /etc/default before bailing out

* make init script work properly with /etc/default/weewx

* make output consistent

* more simplification

* keep PEP happy

* avoid resource consumption from slow reports by extending the StdReport.max_wait.  provide log messages when it happens.

* new features have move to the roadmap

* no more todo items left

* do not emit default sensor_map to the config

* aborted attempt to get additional battery status

* bump to 3.7.0b2

* do recipe using wget instead of curl

* forgot the O option to wget

* do not warn when calibrations are ignored - the implementation resulted in too many log entries

* get rid of tabs

* added notes about wmr300 rain counter and logger

* added norwegian 'no data available' as 'Ingen data er tilgjengelige'

* simplify.  eliminate more passive voice and gerunds.

* avoid run-on

* provide better feedback for operational errors.  make manager logging more consistent.

* fix typo in wmr300 ConfEditor

* decode heatindex and windchill from wmr300 sensor outputs

* fixed bad extract_signed invocation

* fixed wmr* partial packets note

* added mysqldb install instructions to userguide

* minor html fixes

* added link to wee_extension

* clarify acurite sensor transmission periods.

* added battery status for all wmr100 remote t/h sensors

* added battery status for all wmr100 remote t sensors

* document changes to wmr100, wmr200, wmr9x8 drivers.  fix 'Calculatios' typo.

* fixed inverted wmr200 battery status

* rename fault_out to out_fault to match pattern of other faults

* make battery status labels consistent across all wmr drivers

* wmr300 driver moves from rc to 0.18

* bump to 3.7.0b3

* css fixes: neutralize the glaring yellow; brighten the note green to more closely match the tone of warning red; @media tweaks to match font changes.

* fix column title

* distinguish selection color from code color

* fixed shift bug in weewx-multi

* Fixed (I think) issue #219

* update logwatch script to properly handle revised generator log messages

refer commit
03c3e4ef57 (diff-3cefdd7265f340e9683b0a2d0417b70f)

* normalize the quick-start

* Merge branch 'development', remote branch 'origin'

* fix layout table width on installation pages

* v3.7.0b4

* use released_versions instead of previous_versions

* Merge branch 'development', remote branch 'origin'

* parameterize release rule.  make release rule idempotent.

* replace cheetahtemplate.org with pythonhosted.org

* wee_database --help output was slightly different to reality

* Removed BOM at beginning of customizing.htm

* wee_database --help output was slightly different to reality

* Reworded comment on whether to --update daily summaries.

* cater for change in manager log output

* remove misleading windGustDir info

* bump to 3.7.0

* Added date to change log

* escape the dollars in release target

* fixed log syntax

* adjust log level for wmr100 bad usb report

* emit rapidfire cache info only when debug >= 3

* enable post_interval overrides for WOW uploader

* Fixes issue #230, exception when using Rapidfire with metric units

* Added StdRESTbase back in.

It seems that some uploaders still depend on it.

* Fixed problem that prevented a MySQL port from being specified.

* Added antialias GIF to list of files to be installed.

* Make sure GIF files get uploaded

* distribute examples in a single directory

* distinguish docs/examples vs examples

* Fixed bug that prevented a port from being specified for MySQL installations.

* Removed redundant change log entry

* Add MySQL Error 2003 to exceptions (#234)

* Added PR #234 to change log

* Documented change in location of the examples

* update examples paths in remaining guides.  explicitly list all path changes for examples.

* By default, autocommit is now enabled for the MySQL driver. Fixes issue #237.

Included regression test.
2017-03-20 00:41:34 -07:00

650 lines
25 KiB
Python
Executable File

#!/usr/bin/env python
#
# weewx --- A simple, high-performance weather station server
#
# Copyright (c) 2009-2015 Tom Keffer <tkeffer@gmail.com>
#
# See the file LICENSE.txt for your full rights.
#
"""Customized distutils setup file for weewx."""
from __future__ import with_statement
import os.path
import sys
import re
import tempfile
import shutil
import configobj
from distutils.core import setup
from distutils.command.install import install
from distutils.command.install_data import install_data
from distutils.command.install_lib import install_lib
from distutils.command.install_scripts import install_scripts
from distutils.command.sdist import sdist
import distutils.dir_util
# Useful for debugging setup.py. Set the environment variable
# DISTUTILS_DEBUG to get more debug info.
from distutils.debug import DEBUG
# Find the install bin subdirectory:
this_file = os.path.join(os.getcwd(), __file__)
this_dir = os.path.abspath(os.path.dirname(this_file))
bin_dir = os.path.abspath(os.path.join(this_dir, 'bin'))
# Now that we've found the bin subdirectory, inject it into the path:
sys.path.insert(0, bin_dir)
# Now we can import some weewx modules
import weewx
VERSION = weewx.__version__
import weecfg.extension
import weeutil.weeutil
start_scripts = ['util/init.d/weewx.bsd',
'util/init.d/weewx.debian',
'util/init.d/weewx.lsb',
'util/init.d/weewx.redhat',
'util/init.d/weewx.suse']
# The default station information:
stn_info = {'station_type' : 'Simulator',
'driver' : 'weewx.drivers.simulator'}
#==============================================================================
# install
#==============================================================================
class weewx_install(install):
"""Specialized version of install, which adds a --no-prompt option to
the 'install' command."""
# Add an option for --no-prompt:
user_options = install.user_options + [('no-prompt', None, 'Do not prompt for station info')]
def initialize_options(self, *args, **kwargs):
install.initialize_options(self, *args, **kwargs)
self.no_prompt = None
def finalize_options(self):
install.finalize_options(self)
if self.no_prompt is None:
self.no_prompt = False
#==============================================================================
# install_lib
#==============================================================================
class weewx_install_lib(install_lib):
"""Specialized version of install_lib, which backs up old bin subdirectories."""
def run(self):
# Determine whether the user is still using an old-style schema
schema_type = get_schema_type(self.install_dir)
# Save any existing 'bin' subdirectory:
if os.path.exists(self.install_dir):
bin_savedir = weeutil.weeutil.move_with_timestamp(self.install_dir)
print "Saved bin subdirectory as %s" % bin_savedir
else:
bin_savedir = None
# Run the superclass's version. This will install all incoming files.
install_lib.run(self)
# If the bin subdirectory previously existed, and if it included
# a 'user' subsubdirectory, then restore it
if bin_savedir:
user_backupdir = os.path.join(bin_savedir, 'user')
if os.path.exists(user_backupdir):
user_dir = os.path.join(self.install_dir, 'user')
distutils.dir_util.copy_tree(user_backupdir, user_dir)
# But, there is one exception: if the old user subdirectory included an
# old-style schema, then it should be overwritten with the new version.
if schema_type == 'old':
incoming_schema_path = os.path.join(bin_dir, 'user/schemas.py')
target_path = os.path.join(self.install_dir, 'user/schemas.py')
distutils.file_util.copy_file(incoming_schema_path, target_path)
#==============================================================================
# install_data
#==============================================================================
class weewx_install_data(install_data):
"""Specialized version of install_data. Mostly, it deals with upgrading
and merging any old weewx.conf configuration files."""
def initialize_options(self):
# Initialize my superclass's options:
install_data.initialize_options(self)
# Set to None so we inherit whatever setting comes from weewx_install:
self.no_prompt = None
def finalize_options(self):
# Finalize my superclass's options:
install_data.finalize_options(self)
# This will set no_prompt to whatever is in weewx_install:
self.set_undefined_options('install', ('no_prompt', 'no_prompt'))
def copy_file(self, f, install_dir, **kwargs):
# If this is the configuration file, then merge it instead
# of copying it
if f == 'weewx.conf':
rv = self.process_config_file(f, install_dir, **kwargs)
elif f in start_scripts:
rv = self.massage_start_file(f, install_dir, **kwargs)
else:
rv = install_data.copy_file(self, f, install_dir, **kwargs)
return rv
def run(self):
# If there is an existing skins subdirectory, do not overwrite it.
if os.path.exists(os.path.join(self.install_dir, 'skins')):
# Do this by filtering it out of the list of subdirectories to
# be installed:
self.data_files = filter(lambda dat : not dat[0].startswith('skins/'), self.data_files)
remove_obsolete_files(self.install_dir)
# Run the superclass's run():
install_data.run(self)
def process_config_file(self, f, install_dir, **kwargs):
global stn_info
# Open up and parse the distribution config file:
try:
dist_config_dict = configobj.ConfigObj(f, file_error=True)
except IOError, e:
sys.exit(str(e))
except SyntaxError, e:
sys.exit("Syntax error in distribution configuration file '%s': %s"
% (f, e))
# The path where the weewx.conf configuration file will be installed
install_path = os.path.join(install_dir, os.path.basename(f))
# Do we have an old config file?
if os.path.isfile(install_path):
# Yes. Read it
config_path, config_dict = weecfg.read_config(install_path, None)
if DEBUG:
print "Old configuration file found at", config_path
# Update the old configuration file to the current version,
# then merge it into the distribution file
weecfg.update_and_merge(config_dict, dist_config_dict)
else:
# No old config file. Use the distribution file, then, if we can,
# prompt the user for station specific info
config_dict = dist_config_dict
if not self.no_prompt:
# Prompt the user for the station information:
stn_info = weecfg.prompt_for_info()
driver = weecfg.prompt_for_driver(stn_info.get('driver'))
stn_info['driver'] = driver
stn_info.update(weecfg.prompt_for_driver_settings(driver))
if DEBUG:
print "Station info =", stn_info
weecfg.modify_config(config_dict, stn_info, DEBUG)
# Set the WEEWX_ROOT
config_dict['WEEWX_ROOT'] = os.path.normpath(install_dir)
# Finally, reorder it to the canonical form
weecfg.reorder_to_ref(config_dict)
# NB: use mkstemp instead of NamedTemporaryFile because we need to
# do the delete (windows gets mad otherwise) and there is no delete
# parameter in NamedTemporaryFile in python 2.5.
# Time to write it out. Get a temporary file:
tmpfd, tmpfn = tempfile.mkstemp()
tmpfile = open(tmpfn, 'w')
# Write the finished configuration file to it:
config_dict.write(tmpfile)
tmpfile.flush()
tmpfile.close()
os.close(tmpfd)
# Save the old config file if it exists:
if not self.dry_run and os.path.exists(install_path):
backup_path = weeutil.weeutil.move_with_timestamp(install_path)
print "Saved old configuration file as %s" % backup_path
# Now install the temporary file (holding the merged config data)
# into the proper place:
rv = install_data.copy_file(self, tmpfn, install_path, **kwargs)
# Now get rid of the temporary file
os.remove(tmpfn)
# Set the permission bits unless this is a dry run:
if not self.dry_run:
shutil.copymode(f, install_path)
return rv
def massage_start_file(self, f, install_dir, **kwargs):
outname = os.path.join(install_dir, os.path.basename(f))
sre = re.compile(r"WEEWX_ROOT\s*=")
with open(f, 'r') as infile:
with tempfile.NamedTemporaryFile("w") as tmpfile:
for line in infile:
if sre.match(line):
tmpfile.writelines("WEEWX_ROOT=%s\n" % self.install_dir)
else:
tmpfile.writelines(line)
tmpfile.flush()
rv = install_data.copy_file(self, tmpfile.name, outname, **kwargs)
# Set the permission bits unless this is a dry run:
if not self.dry_run:
shutil.copymode(f, outname)
return rv
#==============================================================================
# install_scripts
#==============================================================================
class weewx_install_scripts(install_scripts):
def run(self):
# Run the superclass's version:
install_scripts.run(self)
#==============================================================================
# sdist
#==============================================================================
class weewx_sdist(sdist):
"""Specialized version of sdist which checks for password information in
the configuration file before creating the distribution.
For other sdist methods, see:
http://epydoc.sourceforge.net/stdlib/distutils.command.sdist.sdist-class.html
"""
def copy_file(self, f, install_dir, **kwargs):
"""Specialized version of copy_file that checks for stray passwords."""
# If this is the configuration file, then check it for passwords
if f == 'weewx.conf':
import configobj
config = configobj.ConfigObj(f)
try:
password = config['StdReport']['FTP']['password']
sys.exit("\n*** FTP password found in configuration file. Aborting ***\n\n")
except KeyError:
pass
try:
password = config['StdRESTful']['Wunderground']['password']
if password != 'replace_me':
sys.exit("\n*** Wunderground password found in configuration file. Aborting ***\n\n")
except KeyError:
pass
try:
password = config['StdRESTful']['PWSweather']['password']
if password != 'replace_me':
sys.exit("\n*** PWSweather password found in configuration file. Aborting ***\n\n")
except KeyError:
pass
# Pass on to my superclass:
return sdist.copy_file(self, f, install_dir, **kwargs)
#==============================================================================
# utility functions
#==============================================================================
def remove_obsolete_files(install_dir):
"""Remove no longer needed files from the installation
directory, nominally /home/weewx."""
# If the file #upstream.last exists, delete it, as it is no longer used.
try:
os.remove(os.path.join(install_dir, 'public_html/#upstream.last'))
except OSError:
pass
# If the file $WEEWX_INSTALL/readme.htm exists, delete it. It's
# the old readme (since replaced with README)
try:
os.remove(os.path.join(install_dir, 'readme.htm'))
except OSError:
pass
# If the file $WEEWX_INSTALL/CHANGES.txt exists, delete it. It's
# been moved to the docs subdirectory and renamed
try:
os.remove(os.path.join(install_dir, 'CHANGES.txt'))
except OSError:
pass
# The directory start_scripts is no longer used
shutil.rmtree(os.path.join(install_dir, 'start_scripts'), True)
# The file docs/README.txt is now gone
try:
os.remove(os.path.join(install_dir, 'docs/README.txt'))
except OSError:
pass
# If the file docs/CHANGES.txt exists, delete it. It's been renamed
# to docs/changes.txt
try:
os.remove(os.path.join(install_dir, 'docs/CHANGES.txt'))
except OSError:
pass
# setup.py is no longer left in WEEWX_ROOT.
try:
os.remove(os.path.join(install_dir, 'setup.py'))
except OSError:
pass
def get_schema_type(bin_dir):
"""Checks whether the schema in user.schemas is a new style or old style
schema.
bin_dir: The directory to be checked. This is nominally /home/weewx/bin.
Returns:
'none': There is no schema at all.
'old' : It is an old-style schema.
'new' : It is a new-style schema
"""
tmp_path = list(sys.path)
sys.path.insert(0, bin_dir)
try:
import user.schemas
except ImportError:
# There is no existing schema at all.
result = 'none'
else:
# There is a schema. Determine if it is old-style or new-style
try:
# Try the old style 'drop_list'. If it fails, it must be
# a new-style schema
_ = user.schemas.drop_list # @UnusedVariable @UndefinedVariable
except AttributeError:
# New style schema
result = 'new'
else:
# It did not fail. Must be an old-style schema
result = 'old'
finally:
del user.schemas
# Restore the path
sys.path = tmp_path
return result
#==============================================================================
# main entry point
#==============================================================================
if __name__ == "__main__":
setup(name='weewx',
version=VERSION,
description='weather software',
long_description="weewx interacts with a weather station to produce graphs, "
"reports, and HTML pages. weewx can upload data to services such as the "
"WeatherUnderground, PWSweather.com, or CWOP.",
author='Tom Keffer',
author_email='tkeffer@gmail.com',
url='http://www.weewx.com',
license='GPLv3',
classifiers=['Development Status :: 5 - Production/Stable',
'Intended Audience :: End Users/Desktop',
'License :: GPLv3',
'Operating System :: OS Independent',
'Programming Language :: Python',
'Programming Language :: Python :: 2'],
requires=['configobj(>=4.5)',
'serial(>=2.3)',
'Cheetah(>=2.0)',
'sqlite3(>=2.5)',
'PIL(>=1.1.6)'],
provides=['weedb',
'weeplot',
'weeutil',
'weewx'],
cmdclass={"sdist": weewx_sdist,
"install": weewx_install,
"install_scripts": weewx_install_scripts,
"install_data": weewx_install_data,
"install_lib": weewx_install_lib},
platforms=['any'],
package_dir={'': 'bin'},
packages=['schemas',
'user',
'weecfg',
'weedb',
'weeimport',
'weeplot',
'weeutil',
'weewx',
'weewx.drivers'],
py_modules=['daemon'],
scripts=['bin/wee_config',
'bin/wee_database',
'bin/wee_debug',
'bin/wee_device',
'bin/wee_extension',
'bin/wee_import',
'bin/wee_reports',
'bin/weewxd',
'bin/wunderfixer'],
data_files=[
('',
['LICENSE.txt',
'README',
'weewx.conf']),
('docs',
['docs/changes.txt',
'docs/copyright.htm',
'docs/customizing.htm',
'docs/debian.htm',
'docs/devnotes.htm',
'docs/hardware.htm',
'docs/macos.htm',
'docs/readme.htm',
'docs/redhat.htm',
'docs/setup.htm',
'docs/suse.htm',
'docs/upgrading.htm',
'docs/usersguide.htm',
'docs/utilities.htm']),
('docs/css',
['docs/css/jquery.tocify.css',
'docs/css/weewx_docs.css']),
('docs/css/ui-lightness',
['docs/css/ui-lightness/jquery-ui-1.10.4.custom.css',
'docs/css/ui-lightness/jquery-ui-1.10.4.custom.min.css']),
('docs/css/ui-lightness/images',
['docs/css/ui-lightness/images/animated-overlay.gif',
'docs/css/ui-lightness/images/ui-bg_diagonals-thick_18_b81900_40x40.png',
'docs/css/ui-lightness/images/ui-bg_diagonals-thick_20_666666_40x40.png',
'docs/css/ui-lightness/images/ui-bg_flat_10_000000_40x100.png',
'docs/css/ui-lightness/images/ui-bg_glass_100_f6f6f6_1x400.png',
'docs/css/ui-lightness/images/ui-bg_glass_100_fdf5ce_1x400.png',
'docs/css/ui-lightness/images/ui-bg_glass_65_ffffff_1x400.png',
'docs/css/ui-lightness/images/ui-bg_gloss-wave_35_f6a828_500x100.png',
'docs/css/ui-lightness/images/ui-bg_highlight-soft_100_eeeeee_1x100.png',
'docs/css/ui-lightness/images/ui-bg_highlight-soft_75_ffe45c_1x100.png',
'docs/css/ui-lightness/images/ui-icons_222222_256x240.png',
'docs/css/ui-lightness/images/ui-icons_228ef1_256x240.png',
'docs/css/ui-lightness/images/ui-icons_ef8c08_256x240.png',
'docs/css/ui-lightness/images/ui-icons_ffd27a_256x240.png',
'docs/css/ui-lightness/images/ui-icons_ffffff_256x240.png']),
('docs/images',
['docs/images/antialias.gif',
'docs/images/day-gap-not-shown.png',
'docs/images/day-gap-showing.png',
'docs/images/daycompare.png',
'docs/images/daytemp_with_avg.png',
'docs/images/daywindvec.png',
'docs/images/ferrites.jpg',
'docs/images/funky_degree.png',
'docs/images/image_parts.png',
'docs/images/image_parts.xcf',
'docs/images/logo-apple.png',
'docs/images/logo-centos.png',
'docs/images/logo-debian.png',
'docs/images/logo-fedora.png',
'docs/images/logo-linux.png',
'docs/images/logo-mint.png',
'docs/images/logo-opensuse.png',
'docs/images/logo-redhat.png',
'docs/images/logo-suse.png',
'docs/images/logo-ubuntu.png',
'docs/images/logo-weewx.png',
'docs/images/sample_monthrain.png',
'docs/images/weekgustoverlay.png',
'docs/images/weektempdew.png',
'docs/images/yearhilow.png']),
('docs/js',
['docs/js/jquery-1.11.1.min.js',
'docs/js/jquery-ui-1.10.4.custom.min.js',
'docs/js/jquery.tocify-1.9.0.js',
'docs/js/jquery.tocify-1.9.0.min.js',
'docs/js/weewx.js']),
('docs/examples',
['docs/examples/tag.htm']),
('examples',
['examples/alarm.py',
'examples/lowBattery.py',
'examples/mem.py',
'examples/stats.py',
'examples/transfer_db.py']),
('examples/basic',
['examples/basic/changelog',
'examples/basic/install.py',
'examples/basic/readme.txt']),
('examples/basic/skins/basic',
['examples/basic/skins/basic/basic.css',
'examples/basic/skins/basic/current.inc',
'examples/basic/skins/basic/favicon.ico',
'examples/basic/skins/basic/hilo.inc',
'examples/basic/skins/basic/index.html.tmpl',
'examples/basic/skins/basic/skin.conf']),
('examples/fileparse',
['examples/fileparse/changelog',
'examples/fileparse/install.py',
'examples/fileparse/readme.txt']),
('examples/fileparse/bin/user',
['examples/fileparse/bin/user/fileparse.py']),
('examples/pmon',
['examples/pmon/changelog',
'examples/pmon/install.py',
'examples/pmon/readme.txt']),
('examples/pmon/bin/user',
['examples/pmon/bin/user/pmon.py']),
('examples/pmon/skins/pmon',
['examples/pmon/skins/pmon/index.html.tmpl',
'examples/pmon/skins/pmon/skin.conf']),
('examples/xstats',
['examples/xstats/changelog',
'examples/xstats/install.py',
'examples/xstats/readme.txt']),
('examples/xstats/bin/user',
['examples/xstats/bin/user/xstats.py']),
('examples/xstats/skins/xstats',
['examples/xstats/skins/xstats/index.html.tmpl',
'examples/xstats/skins/xstats/skin.conf']),
('skins/Ftp',
['skins/Ftp/skin.conf']),
('skins/Rsync',
['skins/Rsync/skin.conf']),
('skins/Standard',
['skins/Standard/favicon.ico',
'skins/Standard/index.html.tmpl',
'skins/Standard/mobile.css',
'skins/Standard/mobile.html.tmpl',
'skins/Standard/month.html.tmpl',
'skins/Standard/skin.conf',
'skins/Standard/week.html.tmpl',
'skins/Standard/weewx.css',
'skins/Standard/year.html.tmpl']),
('skins/Standard/NOAA',
['skins/Standard/NOAA/NOAA-YYYY-MM.txt.tmpl',
'skins/Standard/NOAA/NOAA-YYYY.txt.tmpl']),
('skins/Standard/RSS',
['skins/Standard/RSS/weewx_rss.xml.tmpl']),
('skins/Standard/backgrounds',
['skins/Standard/backgrounds/band.gif',
'skins/Standard/backgrounds/butterfly.jpg',
'skins/Standard/backgrounds/drops.gif',
'skins/Standard/backgrounds/flower.jpg',
'skins/Standard/backgrounds/leaf.jpg',
'skins/Standard/backgrounds/night.gif']),
('skins/Standard/smartphone',
['skins/Standard/smartphone/barometer.html.tmpl',
'skins/Standard/smartphone/custom.js',
'skins/Standard/smartphone/humidity.html.tmpl',
'skins/Standard/smartphone/index.html.tmpl',
'skins/Standard/smartphone/radar.html.tmpl',
'skins/Standard/smartphone/rain.html.tmpl',
'skins/Standard/smartphone/temp_outside.html.tmpl',
'skins/Standard/smartphone/wind.html.tmpl']),
('skins/Standard/smartphone/icons',
['skins/Standard/smartphone/icons/icon_ipad_x1.png',
'skins/Standard/smartphone/icons/icon_ipad_x2.png',
'skins/Standard/smartphone/icons/icon_iphone_x1.png',
'skins/Standard/smartphone/icons/icon_iphone_x2.png']),
('util/apache/conf.d',
['util/apache/conf.d/weewx.conf']),
('util/import',
['util/import/csv-example.conf',
'util/import/cumulus-example.conf',
'util/import/wu-example.conf']),
('util/init.d',
['util/init.d/weewx.bsd',
'util/init.d/weewx.debian',
'util/init.d/weewx.lsb',
'util/init.d/weewx.redhat',
'util/init.d/weewx.suse']),
('util/launchd',
['util/launchd/com.weewx.weewxd.plist']),
('util/logrotate.d',
['util/logrotate.d/weewx']),
('util/logwatch/conf/logfiles',
['util/logwatch/conf/logfiles/weewx.conf']),
('util/logwatch/conf/services',
['util/logwatch/conf/services/weewx.conf']),
('util/logwatch/scripts/services',
['util/logwatch/scripts/services/weewx']),
('util/newsyslog.d',
['util/newsyslog.d/weewx.conf']),
('util/rsyslog.d',
['util/rsyslog.d/weewx.conf']),
('util/systemd',
['util/systemd/weewx.service']),
('util/udev/rules.d',
['util/udev/rules.d/acurite.rules',
'util/udev/rules.d/cc3000.rules',
'util/udev/rules.d/fousb.rules',
'util/udev/rules.d/te923.rules',
'util/udev/rules.d/vantage.rules',
'util/udev/rules.d/wmr100.rules',
'util/udev/rules.d/wmr200.rules',
'util/udev/rules.d/wmr300.rules',
'util/udev/rules.d/ws28xx.rules'])
]
)