#!/usr/bin/env python
#
#    Copyright (c) 2009-2016 Tom Keffer <tkeffer@gmail.com> and
#                            Gary Roderick
#
#    See the file LICENSE.txt for your rights.
#
"""Import WeeWX observation data from an external source.

Compatibility:

   wee_import can import from a Comma Separated Values (CSV) format file,
   directly from the historical records of a Weather Underground Personal
   Weather Station or from one or more Cumulus monthly log files. CSV format
   files must have a comma separated list of field names on the first line.

Design

   wee_import utilises a config file (the import config file) and a number of
   command line options to control the import. The config file defines the type
   of input to be performed and the import data source as well as more advanced
   options such as field maps etc. Details of the supported command line
   parameters/options can be viewed by entering wee_import --help at the command
   line. Details of the wee_import config file settings can be found in example
   import config files distributed in the weewx/util/import directory.

   wee_import utilises an abstract base class Source that defines the majority
   of the wee_import functionality. The abstract base class and other supporting
   structures are in bin/weeimport/weeimport.py. Child classes are created from
   the base class for each different import type supported by wee_import. The
   child classes set a number of import type specific properties as well as
   defining a getData() method that reads the raw data to be imported and a
   period_generator() method that generates a sequence of objects to be imported
   (eg monthly log files). This way wee_import can be extended to support other
   sources by defining a new child class, its specific properties as well as
   getData() and period_generator() methods. The child class for a given import
   type are defined in the bin/weeimport/xxximport.py files.

   As with other WeeWX utilities, wee_import advises the user of basic
   configuration, action taken and results via stdout. However, since
   wee_import can make substantial changes to the WeeWX archive, wee_import also
   logs to file by default. This functionality is controlled via a command
   line option.

Prerequisites

   wee_import uses a number of WeeWX API calls and therefore must have a
   functional WeeWX installation. wee_import requires WeeWX 3.6.0 or later.

Configuration

   A number of parameters can be defined in the import config file as follows:

# EXAMPLE WEE_IMPORT CONFIGURATION FILE
#
# Copyright (c) 2009-2016 Tom Keffer <tkeffer@gmail.com>
# See the file LICENSE.txt for your rights.

##############################################################################

# Specify the source. Available options are:
#   CSV - import obs from a single CSV format file
#   WU - import obs from a Weather Underground PWS history
#   Cumulus - import obs from a one or more Cumulus monthly log files
# Format is:
#   source = (CSV | WU | Cumulus)
source = Cumulus

##############################################################################

[CSV]
    # Parameters used when importing from a CSV file

    # Path and name of our CSV source file. Format is:
    #   file = full path and filename
    file = /weeimport/var/cumulus/oct19log.csv

    # If there is no mapped interval field how will the interval field be
    # determined for the imported records. Available options are:
    #   derive - Derive the interval field from the timestamp of successive
    #            records. This setting is best used when the imported records
    #            are equally spaced in time and there are no missing records.
    #   conf   - Use the interval setting from weewx.conf. This setting is
    #            best used if the records to be imported have been produced by
    #            WeeWX using the same archive interval as set in weewx.conf on
    #            this machine.
    #   x      - Use a fixed interval of x minutes for every record. This
    #            setting is best used if the records to be imported are
    #            equally based in time but there are some missing records.
    #
    # Note: If there is a mapped interval field then this setting will be
    #       ignored.
    # Format is:
    #   interval = (derive | conf | x)
    interval = 5

    # Should the [StdQC] max/min limits in weewx.conf be applied to the
    # imported data. This may be useful if the source has extreme values that
    # are clearly incorrect for some observations. Available options are:
    #   True  - weewx.conf [StdQC] max/min limits are applied.
    #   False - weewx.conf [StdQC] max/min limits are not applied.
    # Format is:
    #   qc = (True | False)
    qc = True

    # Should any missing derived observations be calculated from the imported
    # data if possible. Available options are:
    #   True  - Any missing derived observations are calculated.
    #   False - Any missing derived observations are not calculated.
    # Format is:
    #   calc_missing = (True | False)
    calc_missing = True

    # Imported records are written to archive in transactions of tranche
    # records at a time. Increase for faster throughput, decrease to reduce
    # memory requirements. Format is:
    #   tranche = x
    # where x is an integer
    tranche = 250

    # Specify whether a UV sensor was used to produce any UV observations.
    # Available options are:
    #   True  - UV sensor was used and UV data will be imported.
    #   False - UV sensor was not used and any UV data will not be imported.
    #           UV fields will be set to None/NULL.
    # For a CSV import UV_sensor should be set to False if a UV sensor was
    # NOT present when the import data was created. Otherwise it may be set to
    # True or omitted. Format is:
    #   UV_sensor = (True | False)
    UV_sensor = True

    # Specify whether a solar radiation sensor was used to produce any solar
    # radiation observations. Available options are:
    #   True  - Solar radiation sensor was used and solar radiation data will
    #           be imported.
    #   False - Solar radiation sensor was not used and any solar radiation
    #           data will not be imported. radiation fields will be set to
    #           None/NULL.
    # For a CSV import solar_sensor should be set to False if a solar radiation
    # sensor was NOT present when the import data was created. Otherwise it may
    # be set to True or omitted. Format is:
    #   solar_sensor = (True | False)
    solar_sensor = True

    # Date-time format of CSV field from which the WeeWX archive record
    # dateTime field is to be extracted. wee_import first attempts to interpret
    # date/time info in this format, if this fails it then attempts to
    # interpret it as a timestamp and if this fails it then raises an error.
    # Uses Python strptime() format codes.
    # raw_datetime_format = Python strptime() format string
    raw_datetime_format = %d-%m-%Y %H:%M:%S

    # Does the imported rain field represent the total rainfall since the last
    # record or a cumulative value. Available options are:
    #   discrete   - rain field represents total rainfall since last record
    #   cumulative - rain field represents a cumulative rainfall reset at
    #                midnight
    # rain = (discrete | cumulative)
    rain = cumulative

    # Lower and upper bounds for imported wind direction. It is possible,
    # particularly for a calculated direction, to have a value (eg -45) outside
    # of the WeeWX limits (0 to 360 inclusive). Format is:
    #
    # wind_direction = lower,upper
    #
    # where :
    #   lower is the lower limit of acceptable wind direction in degrees
    #   (may be negative)
    #   upper is the upper limit of acceptable wind direction in degrees
    #
    # Imported values from lower to upper will be normalised to the range 0 to
    # 360. Values outside of the parameter range will be stored as None. Default
    # is -360,360.
    wind_direction = -360,360

    # Map CSV record fields to WeeWX archive fields. Format is:
    #
    #   weewx_archive_field_name = csv_field_name, weewx_unit_name
    #
    # where:
    #   weewx_archive_field_name - An observation name in the WeeWX database
    #                              schema.
    #   csv_field_name           - The name of a field from the CSV file.
    #   weewx_unit_name          - The name of the units, as defined in WeeWX,
    #                              used by csv_field_name. This value represents
    #                              the units used for this field in the CSV
    #                              file, wee_import will do the necessary
    #                              conversions to the unit system used by the
    #                              WeeWX archive.
    # For example,
    #   outTemp = Temp, degree_C
    # would map the CSV field Temp, in degrees C, to the archive field outTemp.
    #
    # If a field mapping exists for the WeeWX usUnits archive field then the
    # units option may be omitted for each mapped field.
    #
    # WeeWX archive fields that do not exist in the CSV data may be omitted. Any
    # omitted fields that are derived (eg dewpoint) may be calculated during
    # import using the equivalent of the WeeWX StdWXCalculate service through
    # setting the calc-missing parameter above.
    [[FieldMap]]
        dateTime    = timestamp, unix_epoch
        usUnits     =
        interval    =
        barometer   = barometer, hPa
        pressure    =
        altimeter   =
        inTemp      =
        outTemp     = Temp, degree_C
        inHumidity  =
        outHumidity = humidity, percent
        windSpeed   = windspeed, km_per_hour
        windDir     = wind, degree_compass
        windGust    = gust, km_per_hour
        windGustDir = gustDir, degree_compass
        rainRate    = rate, mm_per_hour
        rain        = dayrain, mm
        dewpoint    =
        windchill   =
        heatindex   =
        ET          =
        radiation   =
        UV          =

##############################################################################

[WU]
    # Parameters used when importing from a WU PWS

    # WU PWS Station ID to be used for import.
    station_id = XXXXXXXX123

    #
    # When importing WU data the following WeeWX database fields will be
    # populated directly by the imported data (provided the corresponding data
    # exists on WU):
    #   barometer
    #   dateTime
    #   dewpoint
    #   outHumidity
    #   outTemp
    #   radiation
    #   rain
    #   windDir
    #   windGust
    #   windSpeed
    #
    # The following WeeWX database fields will be populated from other
    # settings/config files:
    #   interval
    #   usUnits
    #
    # The following WeeWX database fields will be populated with values derived
    # from the imported data provided the --calc-missing command line option is
    # used during import:
    #   altimeter
    #   ET
    #   heatindex
    #   pressure
    #   rainRate
    #   windchill
    #
    # The following WeeWX fields will be populated with derived values from the
    # imported data provided the --calc-missing command line option is used
    # during import. These fields will only be saved to the WeeWX database if
    # the WeeWX schema has been modified to accept them. Note that the pyephem
    # module is required in order to calculate maxSolarRad - refer WeeWX Users
    # Guide.
    #   appTemp
    #   cloudbase
    #   humidex
    #   maxSolarRad
    #   windrun

    # How will the interval field be determined for the imported records.
    # Available options are:
    #   derive - Derive the interval field from the timestamp of successive
    #            records. This setting is best used when the imported records
    #            are equally spaced in time and there are no missing records.
    #   conf   - Use the interval setting from weewx.conf. This setting is
    #            best used if the records to be imported have been produced by
    #            WeeWX using the same archive interval as set in weewx.conf on
    #            this machine.
    #   x      - Use a fixed interval of x minutes for every record. This
    #            setting is best used if the records to be imported are
    #            equally based in time but there are some missing records.
    #            This setting is recommended for WU imports.
    # Due to WU frequently missing uploaded records, use of 'derive' may give
    # incorrect or inconsistent interval values. Better results may be
    # achieved by using the 'conf' setting (if WeeWX has been doing the WU
    # uploading and the WeeWX archive_interval matches the WU observation
    # spacing in time) or setting the interval to a fixed value (eg 5). The
    # most appropriate setting will depend on the completeness and (time)
    # accuracy of the WU data being imported.
    # Format is:
    #   interval = (derive | conf | x)
    interval = conf

    # Should the [StdQC] max/min limits in weewx.conf be applied to the
    # imported data. This may be useful if the source has extreme values that
    # are clearly incorrect for some observations. This is particularly useful
    # for WU imports where WU often records clearly erroneous values against
    # obs that are not reported. Available options are:
    #   True  - weewx.conf [StdQC] max/min limits are applied.
    #   False - weewx.conf [StdQC] max/min limits are not applied.
    # Format is:
    #   qc = (True | False)
    qc = True

    # Should any missing derived observations be calculated from the imported
    # data if possible. Available options are:
    #   True  - Any missing derived observations are calculated.
    #   False - Any missing derived observations are not calculated.
    # Format is:
    #   calc_missing = (True | False)
    calc_missing = True

    # Imported records are written to archive in transactions of tranche
    # records at a time. Increase for faster throughput, decrease to reduce
    # memory requirements. Format is:
    #   tranche = x
    # where x is an integer
    tranche = 250

    # Lower and upper bounds for imported wind direction. It is possible,
    # particularly for a calculated direction, to have a value (eg -45) outside
    # of the WeeWX limits (0 to 360 inclusive). Format is:
    #
    # wind_direction = lower,upper
    #
    # where :
    #   lower is the lower limit of acceptable wind direction in degrees
    #   (may be negative)
    #   upper is the upper limit of acceptable wind direction in degrees
    #
    # WU has at times been known to store large values (eg -9999) for wind
    # direction, often no wind direction was uploaded to WU. The wind_direction
    # parameter sets a lower and upper bound for valid wind direction values.
    # Values inside these bounds are normalised to the range 0 to 360. Values
    # outside of the bounds will be stored as None. Default is 0,360
    wind_direction = 0,360

##############################################################################

[Cumulus]
    # Parameters used when importing Cumulus monthly log files
    #
    # Directory containing Cumulus monthly log files to be imported. Format is:
    #   directory = full path without trailing /
    directory = /weeimport/var/cumulus

    # When importing Cumulus monthly log file data the following WeeWX database
    # fields will be populated directly by the imported data:
    #   barometer
    #   dateTime
    #   dewpoint
    #   heatindex
    #   inHumidity
    #   inTemp
    #   outHumidity
    #   outTemp
    #   radiation   (if Cumulus data available)
    #   rain        (requires Cumulus 1.9.4 or later)
    #   rainRate
    #   UV          (if Cumulus data available)
    #   windDir
    #   windGust
    #   windSpeed
    #   windchill
    #
    # The following WeeWX database fields will be populated from other
    # settings/config files:
    #   interval
    #   usUnits
    #
    # The following WeeWX database fields will be populated with values derived
    # from the imported data provided the --calc-missing command line option is
    # used during import:
    #   altimeter
    #   ET
    #   pressure
    #
    # The following WeeWX fields will be populated with derived values from the
    # imported data provided the --calc-missing command line option is used
    # during import. These fields will only be saved to the WeeWX database if
    # the WeeWX schema has been modified to accept them. Note that the pyephem
    # module is required in order to calculate maxSolarRad - refer WeeWX Users
    # Guide.
    #   appTemp
    #   cloudbase
    #   humidex
    #   maxSolarRad
    #   windrun

    # How will the interval field be determined for the imported records.
    # Available options are:
    #   derive - Derive the interval field from the timestamp of successive
    #            records. This setting is best used when the imported records
    #            are equally spaced in time and there are no missing records.
    #   conf   - Use the interval setting from weewx.conf. This setting is
    #            best used if the records to be imported have been produced by
    #            WeeWX using the same archive interval as set in weewx.conf on
    #            this machine.
    #   x      - Use a fixed interval of x minutes for every record. This
    #            setting is best used if the records to be imported are
    #            equally based in time but there are some missing records.
    #            This setting is recommended for WU imports.
    # To import Cumulus records it is recommended that the interval setting
    # be set to the value used in Cumulus as the 'data log interval'.
    # Format is:
    #   interval = (derive | conf | x)
    interval = conf

    # Should the [StdQC] max/min limits in weewx.conf be applied to the
    # imported data. This may be useful if the source has extreme values that
    # are clearly incorrect for some observations. Available options are:
    #   True  - weewx.conf [StdQC] max/min limits are applied.
    #   False - weewx.conf [StdQC] max/min limits are not applied.
    # Format is:
    #   qc = (True | False)
    qc = True

    # Should any missing derived observations be calculated from the imported
    # data if possible. Available options are:
    #   True  - Any missing derived observations are calculated.
    #   False - Any missing derived observations are not calculated.
    # Format is:
    #   calc_missing = (True | False)
    calc_missing = True

    # Specify the character used as the field delimiter as Cumulus monthly log
    # files may not always use a comma to delimit fields in the monthly log
    # files. The character must be enclosed in quotes. Must not be the same
    # as the decimal setting below. Format is:
    #   delimiter = ','
    delimiter = ';'

    # Specify the character used as the decimal point. Cumulus monthly log
    # files may not always use a fullstop character as the decimal point. The
    # character must be enclosed in quotes. Must not be the same as the
    # delimiter setting. Format is:
    #   decimal = '.'
    decimal = ','

    # Imported records are written to archive in transactions of tranche
    # records at a time. Increase for faster throughput, decrease to reduce
    # memory requirements. Format is:
    #   tranche = x
    # where x is an integer
    tranche = 250

    # Specify whether a UV sensor was used to produce any UV observations.
    # Available options are:
    #   True  - UV sensor was used and UV data will be imported.
    #   False - UV sensor was not used and any UV data will not be imported.
    #           UV fields will be set to None/NULL.
    # For a Cumulus monthly log file import UV_sensor should be set to False if
    # a UV sensor was NOT present when the import data was created. Otherwise
    # it may be set to True or omitted. Format is:
    #   UV_sensor = (True | False)
    UV_sensor = True

    # Specify whether a solar radiation sensor was used to produce any solar
    # radiation observations. Available options are:
    #   True  - Solar radiation sensor was used and solar radiation data will
    #           be imported.
    #   False - Solar radiation sensor was not used and any solar radiation
    #           data will not be imported. radiation fields will be set to
    #           None/NULL.
    # For a Cumulus monthly log file import solar_sensor should be set to False
    # if a solar radiation sensor was NOT present when the import data was
    # created. Otherwise it may be set to True or omitted. Format is:
    #   solar_sensor = (True | False)
    solar_sensor = True

    # For correct import of the monthly logs wee_import needs to know what
    # units are used in the imported data. The units used for temperature,
    # pressure, rain and windspeed related observations in the Cumulus monthly
    # logs are set at the Cumulus Station Configuration Screen.  The
    # [[Units]] settings below should be set to the WeeWX equivalent of the
    # units of measure used by Cumulus (eg if Cumulus used 'C' for temperature,
    # temperature should be set to 'degree_C'). Note that Cumulus does not
    # support all units used by WeeWX (eg 'mmHg') so not all WeeWX unit are
    # available options.
    [[Units]]
        temperature = degree_C      # options are 'degree_F' or 'degree_C'
        pressure    = hPa           # options are 'inHg', 'mbar' or 'hPa'
        rain        = mm            # options are 'inch' or 'mm'
        speed       = km_per_hour   # options are 'mile_per_hour',
                                    # 'km_per_hour', 'knot' or
                                    # 'meter_per_second'

##############################################################################

[WeatherCat]
    # Parameters used when importing WeatherCat monthly .cat files
    #
    # Directory containing WeatherCat year folders that contain the monthly
    # .cat files to be imported. Format is:
    #   directory = full path without trailing /
    directory = /var/tmp

    # When importing WeatherCat monthly .cat file data the following WeeWX
    # database fields will be populated directly by the imported data:
    #   barometer
    #   dateTime
    #   dewpoint
    #   inHumidity
    #   inTemp
    #   outHumidity
    #   outTemp
    #   radiation   (if WeatherCat data available)
    #   rain
    #   rainRate
    #   UV          (if WeatherCat data available)
    #   windDir
    #   windGust
    #   windSpeed
    #   windchill
    #
    # The following WeeWX database fields will be populated from other
    # settings/config files:
    #   interval
    #   usUnits
    #
    # The following WeeWX fields will be populated directly by the imported
    # data provided the WeeWX schema has been modified to accept them.
    #   windrun
    #
    # The following WeeWX database fields will be populated with values derived
    # from the imported data provided the --calc-missing command line option is
    # used during import:
    #   altimeter
    #   ET
    #   heatindex
    #   pressure
    #
    # The following WeeWX fields will be populated with derived values from the
    # imported data provided the --calc-missing command line option is used
    # during import. These fields will only be saved to the WeeWX database if
    # the WeeWX schema has been modified to accept them. Note that the pyephem
    # module is required in order to calculate maxSolarRad - refer WeeWX Users
    # Guide.
    #   appTemp
    #   cloudbase
    #   humidex
    #   maxSolarRad

    # How will the interval field be determined for the imported records.
    # Available options are:
    #   derive - Derive the interval field from the timestamp of successive
    #            records. This setting is best used when the imported records
    #            are equally spaced in time and there are no missing records.
    #   conf   - Use the interval setting from weewx.conf. This setting is
    #            best used if the records to be imported have been produced by
    #            WeeWX using the same archive interval as set in weewx.conf on
    #            this machine.
    #   x      - Use a fixed interval of x minutes for every record. This
    #            setting is best used if the records to be imported are
    #            equally based in time but there are some missing records.
    #            This setting is recommended for WU imports.
    # To import WeatherCat records it is recommended that the interval setting
    # be set to the Sampling Rate setting used by WeatherCat as set on the
    # Misc2 tab under WeatherCat Preferences unless the Adaptive Sampling Rate
    # was used in which case interval = derive should be used.
    # Format is:
    #   interval = (derive | conf | x)
    interval = x

    # Should the [StdQC] max/min limits in weewx.conf be applied to the
    # imported data. This may be useful if the source has extreme values that
    # are clearly incorrect for some observations. Available options are:
    #   True  - weewx.conf [StdQC] max/min limits are applied.
    #   False - weewx.conf [StdQC] max/min limits are not applied.
    # Format is:
    #   qc = (True | False)
    qc = True

    # Should any missing derived observations be calculated from the imported
    # data if possible. Available options are:
    #   True  - Any missing derived observations are calculated.
    #   False - Any missing derived observations are not calculated.
    # Format is:
    #   calc_missing = (True | False)
    calc_missing = True

    # Specify the character used as the decimal point. WeatherCat monthly .cat
    # files may not always use a fullstop character as the decimal point. The
    # character must be enclosed in quotes. Format is:
    #   decimal = '.'
    decimal = '.'

    # Imported records are written to archive in transactions of tranche
    # records at a time. Increase for faster throughput, decrease to reduce
    # memory requirements. Format is:
    #   tranche = x
    # where x is an integer
    tranche = 250

    # Specify whether a UV sensor was used to produce any UV observations.
    # Available options are:
    #   True  - UV sensor was used and UV data will be imported.
    #   False - UV sensor was not used and any UV data will not be imported.
    #           UV fields will be set to None/NULL.
    # For a WeatherCat monthly .cat file import UV_sensor should be set to
    # False if a UV sensor was NOT present when the import data was created.
    # Otherwise it may be set to True or omitted. Format is:
    #   UV_sensor = (True | False)
    UV_sensor = True

    # Specify whether a solar radiation sensor was used to produce any solar
    # radiation observations. Available options are:
    #   True  - Solar radiation sensor was used and solar radiation data will
    #           be imported.
    #   False - Solar radiation sensor was not used and any solar radiation
    #           data will not be imported. radiation fields will be set to
    #           None/NULL.
    # For a WeatherCat monthly .cat file import solar_sensor should be set to
    # False if a solar radiation sensor was NOT present when the import data
    # was created. Otherwise it may be set to True or omitted. Format is:
    #   solar_sensor = (True | False)
    solar_sensor = True

Adding a New Import Source

    To add a new import source:

    -   Create a new file bin/weeimport/xxximport.py that defines a new class
        for the xxx source that is a child of class Source. The new class must
        meet the following minimum requirements:

        -   __init__() must define:

            -   self.raw_datetime_format: Format of date time data field from
                                          which observation timestamp is to be
                                          derived. String comprising Python
                                          strptime() format codes.
            -   self.rain: Whether imported rainfall field contains the
                           rainfall since the last record or a cumulative value.
                           String 'discrete' or 'cumulative'
            -   self.wind_dir: The range of values in degrees that will be
                               accepted as a valid wind direction. Two way
                               tuple of the format (lower, upper) where lower
                               is the lower inclusive limit and upper is the
                               upper inclusive limit.

        -   Define a period_generator() method that:

            -   Accepts no parameters and generates (yields) a sequence of
                objects (eg file names, dates for a http request etc) that are
                passed to the getRawData() method to obtain a sequence of raw
                data records.

        -   Define a getRawdata() method that:

            -   Accepts a single parameter 'period' that is provided by the
                period_generator() method.

            -   Returns an iterable of raw source data records.

            -   Creates the source data field-to-WeeWX archive field map and
                saves the map to the class object map property (the map may be
                created using the Source.parseMap() method). Refer to
                getRawData() methods in csvimport.py and wuimport.py.

    -   Modify bin/weeimport/weeimport.py as follows:

        -   Add a new entry to the list of supported services defined in
            SUPPORTED_SERVICES.

    -   Create a wee_import import config file for importing from the new
        source. The import config file must:

        -   Add a new source name to the source parameter. The new source name
            must be the same (case sensitive) as the entry added to
            weeimport.py SUPPORTED_SERVICES.

        -   Define a stanza for the new import type. The stanza must be the
            same (case sensitive) as the entry added to weeimport.py
            SUPPORTED_SERVICES.
"""

# Python imports
import optparse
import syslog

from distutils.version import StrictVersion

# WeeWX imports
import weewx
import weeimport
import weeimport.weeimport

# wee_import version number
WEE_IMPORT_VERSION = '0.3'
# minimum WeeWX version required for this version of wee_import
REQUIRED_WEEWX = "3.6.0"

description = """Import observation data into a WeeWX archive."""

usage = """wee_import --help
       wee_import --version
       wee_import --import-config=IMPORT_CONFIG_FILE
            [--config=CONFIG_FILE]
            [--date=YYYY-mm-dd | --from=YYYY-mm-dd[THH:MM] --to=YYYY-mm-dd[THH:MM]]
            [--dry-run]
            [--verbose]
            [--log=-]
"""

epilog = """wee_import will import data from an external source into a WeeWX
            archive. Daily summaries are updated as each archive record is
            imported so there should be no need to separately rebuild the daily
            summaries using the wee_database utility."""


def main():
    """The main routine that kicks everything off."""

    # Create a command line parser:
    parser = optparse.OptionParser(description=description,
                                   usage=usage,
                                   epilog=epilog)

    # Add the various options:
    parser.add_option("--config", dest="config_path", type=str,
                      metavar="CONFIG_FILE", default="weewx.conf",
                      help="Use WeeWX configuration file CONFIG_FILE.")
    parser.add_option("--import-config", dest="import_config_path", type=str,
                      metavar="IMPORT_CONFIG_FILE",
                      help="Use import configuration file IMPORT_CONFIG_FILE.")
    parser.add_option("--dry-run", dest="dry_run", action="store_true",
                      help="Print what would happen but do not do it.")
    parser.add_option("--date", dest="date", type=str, metavar="YYYY-mm-dd",
                      help="Import data for this date. Format is YYYY-mm-dd.")
    parser.add_option("--from", dest="date_from", type=str, metavar="YYYY-mm-dd[THH:MM]",
                      help="Import data starting at this date or date-time. "
                           "Format is YYYY-mm-dd[THH:MM].")
    parser.add_option("--to", dest="date_to", type=str, metavar="YYYY-mm-dd[THH:MM]",
                      help="Import data up until this date or date-time. Format "
                           "is YYYY-mm-dd[THH:MM].")
    parser.add_option("--log", dest="logging", type=str, metavar="-",
                      help="Control wee_import log output. By default log output "
                           "is sent to the WeeWX log file. Log output may be "
                           "disabled by using '--log=-'. Some WeeWX API log "
                           "output cannot be controlled by wee_import and will "
                           "be sent to the default log file irrespective of the "
                           "'--log' option.")
    parser.add_option("--verbose", action="store_true", dest="verbose",
                      help="Print useful extra output.")
    parser.add_option("--version", dest="version", action="store_true",
                      help="Display wee_import version number.")

    # Now we are ready to parse the command line:
    (options, args) = parser.parse_args()

    # check WeeWX version number for compatibility
    if StrictVersion(weewx.__version__) < StrictVersion(REQUIRED_WEEWX):
        print "WeeWX %s or greater is required, found %s. Nothing done, exiting." % (REQUIRED_WEEWX,
                                                                                     weewx.__version__)
        exit(1)

    # display wee_import version info
    if options.version:
        print "wee_import version: %s" % WEE_IMPORT_VERSION
        exit(0)

    # Set up logging
    wlog = weeimport.weeimport.WeeImportLog(options.logging,
                                            options.verbose,
                                            options.dry_run)

    # advise the user we are starting up
    wlog.printlog(syslog.LOG_INFO, "Starting wee_import...")

    # If we got this far we must want to import something so get a Source
    # object from our factory and try to import. Be prepared to catch any
    # errors though.
    try:
        source_obj = weeimport.weeimport.Source.sourceFactory(options,
                                                              args,
                                                              wlog)
        source_obj.run()
    except weeimport.weeimport.WeeImportOptionError as e:
        wlog.printlog(syslog.LOG_INFO, "**** Command line option error.")
        wlog.printlog(syslog.LOG_INFO, "**** %s" % e)
        print "**** Nothing done, exiting."
        wlog.logonly(syslog.LOG_INFO, "**** Nothing done.")
        exit(1)
    except weeimport.weeimport.WeeImportIOError as e:
        wlog.printlog(syslog.LOG_INFO, "**** Unable to load source file.")
        wlog.printlog(syslog.LOG_INFO, "**** %s" % e)
        print "**** Nothing done, exiting."
        wlog.logonly(syslog.LOG_INFO, "**** Nothing done.")
        exit(1)
    except weeimport.weeimport.WeeImportFieldError as e:
        wlog.printlog(syslog.LOG_INFO, "**** Unable to map source data.")
        wlog.printlog(syslog.LOG_INFO, "**** %s" % e)
        print "**** Nothing done, exiting."
        wlog.logonly(syslog.LOG_INFO, "**** Nothing done.")
        exit(1)
    except weeimport.weeimport.WeeImportMapError as e:
        wlog.printlog(syslog.LOG_INFO,
                      "**** Unable to parse source-to-WeeWX field map.")
        wlog.printlog(syslog.LOG_INFO, "**** %s" % e)
        print "**** Nothing done, exiting."
        wlog.logonly(syslog.LOG_INFO, "**** Nothing done.")
        exit(1)
    except (weewx.ViolatedPrecondition, weewx.UnsupportedFeature) as e:
        wlog.printlog(syslog.LOG_INFO, "**** %s" % e)
        print "**** Nothing done, exiting."
        wlog.logonly(syslog.LOG_INFO, "**** Nothing done.")
        print
        parser.print_help()
        exit(1)
    except SystemExit as e:
        print e
        exit(0)
    except (ValueError, weewx.UnitError) as e:
        wlog.printlog(syslog.LOG_INFO, "**** %s" % e)
        print "**** Nothing done, exiting."
        wlog.logonly(syslog.LOG_INFO, "**** Nothing done.")
        exit(1)
    except IOError as e:
        wlog.printlog(syslog.LOG_INFO, "**** Unable to load config file.")
        wlog.printlog(syslog.LOG_INFO, "**** %s" % e)
        print "**** Nothing done, exiting."
        wlog.logonly(syslog.LOG_INFO, "**** Nothing done.")
        exit(1)

# execute our main code
if __name__ == "__main__":
    main()