Source code for pywws.service.cwop

# pywws - Python software for USB Wireless Weather Stations
# http://github.com/jim-easterbrook/pywws
# Copyright (C) 2018  pywws contributors

# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.

# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.

# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

"""Upload weather data to Citizen Weather Observer Program.

The `Citizen Weather Observer Program`_ (CWOP) is a north American
public-private partnership to gather weather data. This module uploads
data to it from pywws. You can upload "logged" or "live" data (or both).
The module ensures there is at least 5 minutes between each reading as
required by the API.

* Create account: http://www.wxqa.com/SIGN-UP.html
* API: http://www.wxqa.com/faq.html
* Example ``weather.ini`` configuration::

    [cwop]
    designator = EW9999
    latitude = 5130.06N
    longitude = 00008.52E
    passcode = -1

    [logged]
    services = ['cwop', 'underground']

    [live]
    services = ['cwop', 'underground']

Note that the latitude and longitude must be in "LORAN" format and
leading zeros are required. See question 3 in the `CWOP FAQ`_ for more
information.

Licensed radio hams use their callsign as the designator and need a
passcode. Other users should leave the passcode at its default value of
``-1``.

The CWOP/APRS uploader is based on code by Marco Trevisan <mail@3v1n0.net>.

.. _Citizen Weather Observer Program: http://www.wxqa.com/
.. _CWOP FAQ: http://www.wxqa.com/faq.html

"""

from __future__ import absolute_import, print_function, unicode_literals

from contextlib import closing, contextmanager
from datetime import timedelta
import logging
import os
import socket
import sys

import pywws
import pywws.service

__docformat__ = "restructuredtext en"
service_name = os.path.splitext(os.path.basename(__file__))[0]
logger = logging.getLogger(__name__)


[docs]class ToService(pywws.service.LiveDataService): config = { 'designator': ('', True, 'designator'), 'passcode' : ('-1', True, 'passcode'), 'latitude' : ('', True, 'latitude'), 'longitude' : ('', True, 'longitude'), } fixed_data = {'version': pywws.__version__} interval = timedelta(seconds=290) logger = logger service_name = service_name template = """ #live# 'idx' : #idx "'%d%H%M',"# 'wind_dir' : #wind_dir "'%03.0f'," "'...'," "winddir_degrees(x)"# 'wind_ave' : #wind_ave "'%03.0f'," "'...'," "wind_mph(x)"# 'wind_gust' : #wind_gust "'%03.0f'," "'...'," "wind_mph(x)"# 'temp_out' : #temp_out "'%03.0f'," "'...'," "temp_f(x)"# 'hum_out' : #hum_out "'%02d'," "'..'," "x % 100"# 'rel_pressure' : #rel_pressure "'%05.0f'," "'.....'," "x * 10.0"# 'rain_hour' : #calc "100.0*rain_inch(rain_hour(data))" "'%03.0f'," "'...',"# 'rain_24hr' : #calc "100.0*rain_inch(rain_24hr(data))" "'%03.0f'," "'...',"# """
[docs] @contextmanager def session(self): with closing(socket.socket()) as session: session.settimeout(20) server = ('rotate.aprs.net', 'cwop.aprs.net')[self.fixed_data['passcode'] == '-1'] session.connect((server, 14580)) response = session.recv(4096).decode('ASCII') logger.debug('server software: %s', response.strip()) yield session
[docs] def upload_data(self, session, prepared_data={}): login = ('user {designator:s} pass {passcode:s} ' + 'vers pywws {version:s}\n').format(**prepared_data) logger.debug('login: "{:s}"'.format(login)) login = login.encode('ASCII') packet = ('{designator:s}>APRS,TCPIP*:@{idx:s}' + 'z{latitude:s}/{longitude:s}' + '_{wind_dir:s}/{wind_ave:s}g{wind_gust:s}t{temp_out:s}' + 'r{rain_hour:s}p{rain_24hr:s}b{rel_pressure:s}h{hum_out:s}' + '.pywws-{version:s}\n').format(**prepared_data) logger.debug('packet: "{:s}"'.format(packet)) packet = packet.encode('ASCII') try: session.sendall(login) response = session.recv(4096).decode('ASCII') logger.debug('server login ack: %s', response.strip()) session.sendall(packet) session.shutdown(socket.SHUT_RDWR) except Exception as ex: return False, repr(ex) return True, 'OK'
if __name__ == "__main__": sys.exit(pywws.service.main(ToService))