Support in including Wetternetz Sachsen regional network

59 views
Skip to first unread message

Thomas Walther

unread,
Jun 30, 2019, 9:39:40 AM6/30/19
to weewx-user
Hello, 
we would like to use Weewx to include new stations into our large regional network "Wetternetz Sachsen".
Problem is we have no Python knowdledge and would appreciate support a lot.
We tried to modify code from restx.py but did not work. We got  recommendation to use extension instead.
What we have created so far:


# ==============================================================================
#                    WetternetzSachsen
# ==============================================================================

class WetternetzSachsen(StdRESTful):
"""Upload data to the Wetternetz Sachsen (Saxony - Germany) using protocol WNS V2.1

To enable this module, add the following to weewx.conf:
 
     [StdRESTful]
         [[WetternetzSachsen]]
             enable   = True
             username = StationsID [WNSxxx]
             password = Stationskennung [DirectPost Password]
     
     The WetternetzSachsen-server expects a single string of values delimited by
     semicolons. The position of each value matters, for example position 1
     is the StationsID and position 2 is the Stationskennung [DirectPost Password].

For details of the Wetternetz Sachsen V2.1 protocol and further position of values for the string see
http://www.wetternetz-sachsen.de/download/parameterliste_%20wns_21.txt

# The URL used by Wetternetz Sachsen:
archive_url = "
http://www.wetternetz-sachsen.de/get_daten_21.php"

"""

def __init__(self, engine, config_dict):
         super(StdWetternetzSachsen, self).__init__(engine, config_dict)
 
         site_dict = get_site_dict(
             config_dict, 'WetternetzSachsen', 'station', 'password')
         if site_dict is None:
             return

        site_dict.setdefault('language', 'de')

         # Get the manager dictionary:
        site_dict['manager_dict'] = weewx.manager.get_manager_dict_from_config(
             config_dict, 'wx_binding')
 
        self.archive_queue = Queue.Queue()
         self.archive_thread = WetternetzSachsenThread(self.archive_queue, **site_dict)
         self.archive_thread.start()
         self.bind(weewx.NEW_ARCHIVE_RECORD, self.new_archive_record)
         syslog.syslog(syslog.LOG_INFO, "
restx: WetternetzSachsen: "
                                        "
Data will be uploaded for user %s" %
                       site_dict['username'])
 
 
     def new_archive_record(self, event):
         self.archive_queue.put(event.record)
 
class WetternetzSachsenThread(RESTThread):
"""
Concrete class for threads posting from the archive queue,
       
using the WetternetzSachsen V2.1 protocol."""
     _SERVER_URL = 'http://www.wetternetz-sachsen.de/get_daten_21.php'
     
     def __init__(self, queue, username, password,
                  manager_dict,
                  language='de', server_url=_SERVER_URL,
                  post_interval=300, max_backlog=sys.maxint, stale=None,
                  log_success=True, log_failure=True,
                  timeout=60, max_tries=3, retry_wait=5, retry_login=1800, skip_upload=False):

         """
Initialize an instances of WetternetzSachsenThread.
 
         
Parameters specific to this class:
           username
: StationsID [WNSxxx]
           password
: Stationskennung [DirectPost Password]
           manager_dict
: A dictionary holding the database manager
           information
. It will be used to open a connection to the archive  
           database
.
           server_url
: URL of the server
           
No need to change, Default is the WetternetzSachsen getdaten-php-file
 
         
Parameters customized for this class:
 
           post_interval
: The interval in seconds between posts. The usual upload interval is 300 seconds. So default is set to 300. Intervals between 60 and 3600 seconds are possible but useful are only intervals less than 900 seconds.  """
 
         super(WetternetzSachsenThread, self).__init__(queue,
                                            protocol_name='WetternetzSachsen',
                                            manager_dict=manager_dict,
                                            post_interval=post_interval,
                                            max_backlog=max_backlog,
                                            stale=stale,
                                            log_success=log_success,
                                            log_failure=log_failure,
                                            timeout=timeout,
                                            max_tries=max_tries,
                                            retry_wait=retry_wait,
                                            retry_login=retry_login,
                                            skip_upload=skip_upload)
         self.username = username
         self.password = password
         self.server_url = server_url

     def get_record(self, record, dbmanager):
         # Get the record from my superclass
         r = super(WetternetzSachsenThread, self).get_record(record, dbmanager)
 
     def process_record(self, record, dbmanager):
         r = self.get_record(record, dbmanager)
         url = self.get_url(r)
         if self.skip_upload:
             raise AbortedPost("
Skip post")
         req = urllib2.Request(url)
         req.add_header("
User-Agent", "weewx/%s" % weewx.__version__)
         self.post_with_retries(req)
 
     def check_response(self, response):
"""
Check the HTTP response code for an Ambient related error."""
         for line in response:
             if line.startswith("
Benutzer/Passwort Fehler"):
                 raise BadLogin(line)
             elif not line.startswith('OK'):
                 raise FailedPost("
server returned '%s'" % line)
 
     def get_url(self, in_record):
 
         # Convert to units required by WetternetzSachsen
         record = weewx.units.to_METRIC(in_record)
 
         # assemble an array of values in the proper order
         values = [self.username]
         values = [self.password]
        values.append('WNS V2.1')  # TMPVER
        values.append('WeeWx')  # WSOVER
        time_tt = time.gmtime(record['dateTime'])
        values.append(time.strftime("
%H:%M", time_tt)) # ZEIT__
        values.append(time.strftime("
%d.%m.%Y", time_tt)) # DATUM_
        values.append('-1')  # UTCDIF
        values.append('$current.outTemp')  # T2AKT_
        values.append('$day.outTemp.min')  # T2MIN_
        values.append('$day.outTemp.max')  # T2MAX_
        values.append('$span($hour_delta=1).outTemp')  # T2D1H_
        values.append('$current.extraTemp1')  # T5AKT_
        values.append('$current.extraTemp1')  # T5MIN_
        values.append('$current.outHumidity'))  # LFAKT_
        values.append('$span($time_delta=300).rain.sum') # RRD05_
        values.append('$span($time_delta=600).rain.sum') # RRD10_
        values.append('$span($hour_delta=1).rain.sum') # RRD1H_
        values.append('$span($hour_delta=3).rain.sum') # RRD3H_
        values.append('$span($hour_delta=24).rain.sum') # RRD24H
        values.append('$day.rain.sum')  # RRD1D_
        values.append('$current.wind')  # WSAKT_
        values.append('$current.windDir')  # WRAKT_
        values.append('$current.windGust')  # WBAKT_
        values.append('$span($time_delta=600).wind.avg')  # WSM10_
        values.append('$span($time_delta=600).windDir.avg')  # WRM10_
        values.append('$span($hour_delta=1).wind.max')  # WSMX1H
        values.append('$day.wind.max')  # WSMX1D
        values.append('$day.windGust.max')  # WBMX1D
        values.append('$current.chill')  # WCAKT_   ????????????
        values.append('$span($hour_delta=1).chill.min') # WCMN1H  ??????????
        values.append('$day.chill.min')  # WCMN1D  ??????????
        values.append('$current.barometer')  # LDAKT_
        values.append('$current.pressure')  # LDABS_
        values.append('$span($hour_delta=1).barometer') # LDD1H_
        values.append('$span($hour_delta=3).barometer') # LDD3H_
        values.append('$span($hour_delta=24).barometer') # LDD24H
        values.append('$day.ET.sum')  # EVA1D_
        values.append('--')  # SOD1H_
        values.append('--')  # SOD1D_
        values.append('--')  # BEDGRA
        values.append('$current.radiation')  # SSAKT_
        values.append('$span($hour_delta=1).radiation') # SSMX1H
        values.append('$day.radiation.max')  # SSMX1D
        values.append('$current.UV')  # UVINDX
        values.append('$day.UV.max')  # UVMX1D
        values.append('--')  # WOLKUG
        values.append('--')  # SIWEIT
        values.append('--')  # SNEHOE
        values.append('--')  # SNEDAT
        values.append('--')  # SNEFGR
        values.append('$span($month_delta=1).outTemp.avg')  # T2M1M_
        values.append('--')  # T2M1MA
        values.append('--')  # RRDATU
        values.append('$yesterday.rain.sum')  # RRGEST
        values.append('$month.rain.sum')  # RRD1M_
        values.append('--')  # RRD1MR
        values.append('$year.rain.sum')  # RRD1A_
        values.append('--')  # RRD1AR
        values.append('$month.ET.sum')  # EVAD1M
        values.append('$year.ET.sum')  # EVAD1A
        values.append('--')  # SOD1M_
        values.append('--')  # SOD1A_
        values.append('--')  # SOD1AR
        values.append('--')  # KLTSUM
        values.append('--')  # WRMSUM
        values.append('--')  # GRASUM
        values.append('--')  # GRADAT



 
         valstr = ';'.join(values)
         url = self.server_url + '?val=' + valstr
         # show the url in the logs for debug, but mask any credentials
         if weewx.debug >= 2:
             syslog.syslog(syslog.LOG_DEBUG, 'restx: WetternetzSachsen: url: %s' %
                           re.sub(m.hexdigest(), "
XXX", url))
         return url


# ==============================================================================
#                    Station Registry
# ==============================================================================

class StdStationRegistry(StdRESTful):
    """
Class for phoning home to register a weewx station.

   
To enable this module, add the following to weewx.conf:

   
[StdRESTful]
       
[[StationRegistry]]
            register_this_station
= True

   
This will periodically do a http GET with the following information:

        station_url      
Should be world-accessible. Used as key.
        description      
Brief synopsis of the station
        latitude        
Station latitude in decimal
        longitude        
Station longitude in decimal
        station_type    
The driver name, for example Vantage, FineOffsetUSB
        station_model    
The hardware_name property from the driver
        weewx_info       weewx version
        python_info
        platform_info

   
The station_url is the unique key by which a station is identified.
   
"""

    archive_url = 'http://weewx.com/register/register.cgi'

    def __init__(self, engine, config_dict):

        super(StdStationRegistry, self).__init__(engine, config_dict)

        # Extract a copy of the dictionary with the registry options:
        _registry_dict = accumulateLeaves(config_dict['StdRESTful']['StationRegistry'], max_level=1)

        # Should the service be run?
        if not to_bool(_registry_dict.pop('register_this_station', False)):
            syslog.syslog(syslog.LOG_INFO, "
restx: StationRegistry: "
                                           "
Registration not requested.")
            return

        # Registry requires a valid station url
        _registry_dict.setdefault('station_url',
                                  self.engine.stn_info.station_url)
        if _registry_dict['station_url'] is None:
            syslog.syslog(syslog.LOG_INFO, "
restx: StationRegistry: "
                                           "
Station will not be registered: no station_url specified.")
            return

        _registry_dict.setdefault('station_type', config_dict['Station'].get('station_type', 'Unknown'))
        _registry_dict.setdefault('description', self.engine.stn_info.location)
        _registry_dict.setdefault('latitude', self.engine.stn_info.latitude_f)
        _registry_dict.setdefault('longitude', self.engine.stn_info.longitude_f)
        _registry_dict.setdefault('station_model', self.engine.stn_info.hardware)

        self.archive_queue = Queue.Queue()
        self.archive_thread = StationRegistryThread(self.archive_queue,
                                                    **_registry_dict)
        self.archive_thread.start()
        self.bind(weewx.NEW_ARCHIVE_RECORD, self.new_archive_record)
        syslog.syslog(syslog.LOG_INFO, "
restx: StationRegistry: "
                                       "
Station will be registered.")

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


class StationRegistryThread(RESTThread):
    """
Concrete threaded class for posting to the weewx station registry."""

    def __init__(self, queue, station_url, latitude, longitude,
                 server_url=StdStationRegistry.archive_url,
                 description="
Unknown",
                 station_type="
Unknown", station_model="Unknown",
                 post_interval=604800, max_backlog=0, stale=None,
                 log_success=True, log_failure=True,
                 timeout=60, max_tries=3, retry_wait=5):
        """
Initialize an instance of StationRegistryThread.
       
       
Parameters specific to this class:

          station_url
: An URL used to identify the station. This will be
          used
as the unique key in the registry to identify each station.
         
          latitude
: Latitude of the staion
         
          longitude
: Longitude of the station
       
          server_url
: The URL of the registry server.
         
Default is 'http://weewx.com/register/register.cgi'
         
          description
: A brief description of the station.
         
Default is 'Unknown'
         
          station_type
: The type of station. Generally, this is the name of
          the driver used
by the station.
         
Default is 'Unknown'
         
          station_model
: The hardware model, typically the hardware_name
          property provided
by the driver.
         
Default is 'Unknown'.

       
Parameters customized for this class:
         
          post_interval
: How long to wait between posts.
         
Default is 604800 seconds (1 week).
       
"""

        super(StationRegistryThread, self).__init__(
            queue,
            protocol_name='StationRegistry',
            post_interval=post_interval,
            max_backlog=max_backlog,
            stale=stale,
            log_success=log_success,
            log_failure=log_failure,
            timeout=timeout,
            max_tries=max_tries,
            retry_wait=retry_wait)
        self.station_url = station_url
        self.latitude = to_float(latitude)
        self.longitude = to_float(longitude)
        self.server_url = server_url
        self.description = weeutil.weeutil.list_as_string(description)
        self.station_type = station_type
        self.station_model = station_model

    def get_record(self, dummy_record, dummy_archive):
        _record = dict()
        _record['station_url'] = self.station_url
        _record['description'] = self.description
        _record['latitude'] = self.latitude
        _record['longitude'] = self.longitude
        _record['station_type'] = self.station_type
        _record['station_model'] = self.station_model
        _record['python_info'] = platform.python_version()
        _record['platform_info'] = platform.platform()
        _record['weewx_info'] = weewx.__version__
        _record['usUnits'] = weewx.US
        return _record

    _FORMATS = {'station_url'  : 'station_url=%s',
                'description'  : 'description=%s',
                'latitude'     : 'latitude=%.4f',
                'longitude'    : 'longitude=%.4f',
                'station_type' : 'station_type=%s',
                'station_model': 'station_model=%s',
                'python_info'  : 'python_info=%s',
                'platform_info': 'platform_info=%s',
                'weewx_info'   : 'weewx_info=%s'}

    def format_url(self, record):
        """
Return an URL for posting using the StationRegistry protocol."""

        _liststr = []
        for _key in StationRegistryThread._FORMATS:
            v = record[_key]
            if v is not None:
                _liststr.append(urllib.quote_plus(
                    StationRegistryThread._FORMATS[_key] % v, '='))
        _urlquery = '&'.join(_liststr)
        _url = "
%s?%s" % (self.server_url, _urlquery)
        return _url

    def check_response(self, response):
        """
Check the response from a Station Registry post."""
        for line in response:
            # the server replies to a bad post with a line starting with "
FAIL"
            if line.startswith('FAIL'):
                raise FailedPost(line)

thank you,
Thomas

Karen K

unread,
Nov 5, 2020, 10:03:32 AM11/5/20
to weewx-user
I found that thread by chance, and I did not know that someone tried to write a driver for Wetternetz Sachsen before. I tried it, too, and I was successful so far.
https://github.com/roe-dl/weewx-wns
Reply all
Reply to author
Forward
0 new messages