Hallo 

windy.py

Apr 17 14:15:37 wetter OWFS[22140]: restx: Windy: Failed to publish record 
2019-04-17 14:15:00 CEST (1555503300): Failed upload after 3 tries

api-key  was generated by windy "D....4rKBpgJE0" 32  letter and numbers

Hartmut
# Copyright 2019 Matthew Wall

"""
This is a weewx extension that uploads data to a windy.com

http://windy.com

The protocol is desribed at the windy community forum:

https://community.windy.com/topic/8168/report-you-weather-station-data-to-windy

Minimal configuration

[StdRESTful]
    [[Windy]]
        api_key = API_KEY
        station = STATION_IDENTIFIER
"""

# Python 2/3 compatiblity
try:
    import Queue as queue                   # python 2
    from urllib import urlencode            # python 2
    from urllib2 import Request             # python 2
except ImportError:
    from queue import Queue                          # python 3
    from urllib.parse import urlencode      # python 3
    from urllib.request import Request      # python 3

from distutils.version import StrictVersion
import json
import re
import sys
import syslog
import time
#import urllib

import weewx
import weewx.restx
import weewx.units
from weeutil.weeutil import to_bool

VERSION = "0.1"

REQUIRED_WEEWX = "3.8.0"
if StrictVersion(weewx.__version__) < StrictVersion(REQUIRED_WEEWX):
    raise weewx.UnsupportedFeature("weewx %s or greater is required, found %s"
                                   % (REQUIRED_WEEWX, weewx.__version__))

def logmsg(level, msg):
    syslog.syslog(level, 'restx: Windy: %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 Windy(weewx.restx.StdRESTbase):
    _DEFAULT_URL = 'https://stations.windy.com/pws/update'

    def __init__(self, engine, cfg_dict):
        super(Windy, self).__init__(engine, cfg_dict)        
        loginf("version is %s" % VERSION)
        site_dict = weewx.restx.get_site_dict(cfg_dict, 'Windy',
                                              'api_key', 'station')
        if site_dict is None:
            return
        site_dict.setdefault('server_url', Windy._DEFAULT_URL)

        # FIXME: we should not have to do this here!
        binding = site_dict.pop('binding', 'wx_binding')
        mgr_dict = weewx.manager.get_manager_dict_from_config(
            cfg_dict, binding)

        self.archive_queue = Queue()
        try:
            self.archive_thread = WindyThread(self.archive_queue,
                                              manager_dict=mgr_dict,
                                              **site_dict)
        except weewx.ViolatedPrecondition as e:
            loginf("Data will not be posted: %s" % e)
            return

        self.archive_thread.start()
        self.bind(weewx.NEW_ARCHIVE_RECORD, self.new_archive_record)
        loginf("Data will be uploaded to %s" % site_dict['server_url'])

    def new_archive_record(self, event):
        self.archive_queue.put(event.record)


class WindyThread(weewx.restx.RESTThread):

    def __init__(self, queue, api_key, station, server_url=Windy._DEFAULT_URL,
                 skip_upload=False, manager_dict=None,
                 post_interval=None, max_backlog=sys.maxsize, stale=None,
                 log_success=True, log_failure=True,
                 timeout=60, max_tries=3, retry_wait=5):
        super(WindyThread, self).__init__(queue,
                                          protocol_name='Windy',
                                          manager_dict=manager_dict,
                                          post_interval=post_interval,
                                          max_backlog=max_backlog,
                                          stale=stale,
                                          log_success=log_success,
                                          log_failure=log_failure,
                                          max_tries=max_tries,
                                          timeout=timeout,
                                          retry_wait=retry_wait)
        self.api_key = api_key
        self.station = int(station)
        self.server_url = server_url
        self.skip_upload = to_bool(skip_upload)

    def format_url(self, record):
        data = self.convert_data(record)
        url_data = urlencode(data)
        url = '%s/%s?%s' % (self.server_url, self.api_key, url_data)
        if weewx.debug >= 2:
            logdbg('url: %s' % re.sub(r"api_key=.*", "api_key=XXX", url))
        return url

    # we would like to use POST, but the windy.com servers do not seem to like
    # it when we do that.
#    def get_post_body(self, record):
#        data = self.convert_data(record)
#        obs = {"observations":[data]}
#        return json.dumps(obs), 'application/json'

    def convert_data(self, record):
        rec = weewx.units.to_METRICWX(record)
        data = dict()
        data['station'] = self.station # integer identifier
        data['dateutc'] = time.strftime("%Y-%m-%d %H:%M:%S",
                                        time.gmtime(rec['dateTime']))

        if 'outTemp' in rec:
            data['temp'] = rec['outTemp'] # degree_C
        if 'windSpeed' in rec:
            data['wind'] = rec['windSpeed'] # m/s
        if 'windDir' in rec:
            data['winddir'] = rec['windDir'] # degree
        if 'windGust' in rec:
            data['gust'] = rec['windGust'] # m/s
        if 'outHumidity' in rec:
            data['rh'] = rec['outHumidity'] # percent
        if 'dewpoint' in rec:
            data['dewpoint'] = rec['dewpoint'] # degree_C
        if 'pressure' in rec:
            data['pressure'] = rec['pressure'] # Pa
        if 'barometer' in rec:
            data['baromin'] = rec['barometer'] # inHg # FIXME: need to convert
        if 'hourRain' in rec:
            data['precip'] = rec['hourRain'] # mm in past hour
        if 'UV' in rec:
            data['uv'] = rec['UV']
        return data


# Use this hook to test the uploader:
#   PYTHONPATH=bin python bin/user/windy.py

if __name__ == "__main__":
    class FakeMgr(object):
        table_name = 'fake'
        def getSql(self, query, value):
            return None

    weewx.debug = 2
    queue = Queue()
    t = WindyThread(queue, api_key='123', station=0)
    r = {'dateTime': int(time.time() + 0.5),
         'usUnits': weewx.US,
         'outTemp': 32.5,
         'inTemp': 75.8,
         'outHumidity': 24,
         'windSpeed': 10,
         'windDir': 32}
    print( t.format_url(r))
#    print( t.get_post_body(r))
    t.process_record(r, FakeMgr())

Reply via email to