# $Id: wetter.py 747 2013-12-31 19:13:34Z mwall $
# Copyright 2013 Matthew Wall

#==============================================================================
# wetter.com
#==============================================================================
# Upload data to wetter.com
#  http://wetter.com
#
# Installation:
# 1) put this file in bin/user
# 2) add the following configuration stanza to weewx.conf
# 3) restart weewx
#
# [StdRESTful]
#     ...
#     [[Wetter]]
#         username = USERNAME
#         password = PASSWORD
#         driver = user.wetter.Wetter

import httplib
import socket
import syslog
import time
import urllib
import urllib2

from weewx.restful import REST, SkippedPost, FailedPost
import weewx.units
from weeutil.weeutil import tobool, timestamp_to_string

def logmsg(level, msg):
    syslog.syslog(level, 'wetter: %s' % msg)

def logdbg(msg):
    logmsg(syslog.LOG_DEBUG, msg)

def loginf(msg):
    logmsg(syslog.LOG_INFO, msg)

def logerr(msg):
    logmsg(syslog.LOG_ERR, msg)

class Wetter(REST):
    """Upload using the wetter.com protocol.
    """

    _VERSION = 0.1
    _SERVER_URL = 'http://www.wetterarchiv.de/interface/http/input.php'
    _data_map = {'windrichtung': ('windDir',     '%.0f', 1.0), # degrees
                 'windstaerke':  ('windSpeed',   '%.1f', 0.2777777777), # m/s
                 'temperatur':   ('outTemp',     '%.1f', 1.0), # C
                 'feuchtigkeit': ('outHumidity', '%.0f', 1.0), # percent
                 'luftdruck':    ('barometer',   '%.3f', 1.0), # mbar?
                 'niederschlagsmenge': ('hourRain',    '%.2f', 10.0), # mm
                 }

    def __init__(self, site, **kwargs):
        """Initialize for posting data to wetter.com.

        username: username
        [Required]

        password: password
        [Required]

        interval: The interval in seconds between posts.
        [Optional.  Default is 300]

        max_tries: Maximum number of tries before giving up
        [Optional.  Default is 3]
        
        server_url: Base URL for the server
        [Required]
        """
        self.site = site
        self.server_url = kwargs.get('server_url', self._SERVER_URL)
        self.username = kwargs['username']
        self.password = kwargs['password']
        self.interval = int(kwargs.get('interval', 300))
        self.max_tries = int(kwargs.get('max_tries', 3))
        self.timeout   = int(kwargs.get('timeout', 60))
        self.skip_upload = tobool(kwargs.get('skip_upload', False))
        self._lastpost = None
        # FIXME: restful needs this
        self.station = kwargs.get('station', None)

    def postData(self, archive, time_ts):
        """Post data to the server.

        archive: An instance of weewx.archive.Archive
        
        time_ts: The record desired as a unix epoch time."""
        
        last_ts = archive.lastGoodStamp()

        if time_ts != last_ts:
            msg = "%s: Record %s is not last record" % \
                (self.site, timestamp_to_string(time_ts))
            logdbg(msg)
            raise SkippedPost, msg
        
        if self._lastpost and time_ts - self._lastpost < self.interval:
            msg = "%s: Wait interval (%d) has not passed." % \
                (self.site, self.interval)
            raise SkippedPost, msg

        data = self.getData(archive, time_ts)
        logdbg('data encoded: %s' % urllib.urlencode(data))
        if self.skip_upload:
            raise SkippedPost, 'skip_upload=True'

        for _count in range(self.max_tries):
            # Now use an HTTP POST to post the data.
            try:
                _request = urllib2.Request(self.server_url)
                _request.get_method = lambda: 'POST'
                _request.add_header("User-Agent",
                                    "weewx/%s" % weewx.__version__)
                _response = urllib2.urlopen(_request, urllib.urlencode(data),
                                            self.timeout)
            except (urllib2.URLError, socket.error, httplib.BadStatusLine), e:
                logerr('Failed upload attempt %d to %s: %s' %
                       (_count+1, self.site, e,))
            else:
                txt = _response.read()
                code = _response.getcode()
                logdbg("code: %s" % code)
                logdbg("read: '%s'" % txt)
                if code != 200 :
                    logerr('Failed upload to %s: %s' % (self.site, txt))
                    raise FailedPost, txt
                if not txt.startswith('status=SUCCESS'):
                    logerr('Failed upload to %s: %s' % (self.site, txt))
                    raise FailedPost, txt
                self._lastpost = time_ts
                return
        else:
            msg = 'Failed upload to %s after %d tries' % (
                self.site, self.max_tries)
            logerr(msg)
            raise IOError, msg

    def getData(self, archive, time_ts):
        """Format data for posting.
        
        archive: An instance of weewx.archive.Archive
        
        time_ts: The record desired as a unix epoch time.
        """
        record = self.extractRecordFrom(archive, time_ts)

        # put everything into the right units
        if record['usUnits'] != weewx.METRIC:
            converter = weewx.units.StdUnitConverters[weewx.METRIC]
            record = converter.convertDict(record)

        # put data into expected scaling, structure, and format
        values = {}
        values['benutzername'] = self.username
        values['passwort'] = self.password
        values['niederschlagsmenge_zeit'] = 60
        values['datum'] = time.strftime('%Y%m%d%H%M',
                                        time.gmtime(record['dateTime']))
        for key in self._data_map:
            rkey = self._data_map[key][0]
            if record.has_key(rkey) and record[rkey] is not None:
                v = record[rkey] * self._data_map[key][2]
                values[key] = self._data_map[key][1] % v

        logdbg('data: %s' % values)
        return values
