From: Alexander Vasarab Date: Sun, 29 Nov 2020 20:58:36 +0000 (-0800) Subject: First stab at Python custom Wx implementation X-Git-Tag: v3.0.0^2~1^2~3 X-Git-Url: https://wylark.com/src/infoex-autowx.git/commitdiff_plain/638c4f11d29b685bc7c485c10ce62f2c61ae4a54?ds=sidebyside First stab at Python custom Wx implementation --- diff --git a/README.md b/README.md index b2af012..8bbe60e 100644 --- a/README.md +++ b/README.md @@ -78,11 +78,12 @@ weather station FTP server and other InfoEx-related configuration options. `[station]` -`type = # either mesowest or nrcs #` -`token = # MesoWest API token -- ignored when type is nrcs #` +`type = # mesowest, nrcs, or python #` +`token = # MesoWest API token -- only applies when type is mesowest #` `station_id = # the NRCS/MesoWest identifier for a particular station #` `desired_data = # a comma-delimited list of fields you're interested in #` -`units = # either english or metric -- ignored when type is nrcs #` +`units = # either english or metric -- only applies when type is mesowest #` +`path = # the filesystem path to the Python program -- only applies when type is python #` `[infoex]` `host = # InfoEx FTP host address #` @@ -191,6 +192,13 @@ indicates that I'd like to import "Temperature" and "Precipitation accumulated" from the MesoWest station at Santiam Pass, OR, into InfoEx, and that I want that data in imperial units. +Custom weather station support +------------------------------ + +This program supports custom weather station data by allowing the user +to specify the path to an external Python program. The external Python +program should emit its data in the form expected by infoex-autowx. + A note on supported measurements -------------------------------- diff --git a/infoex-autowx.py b/infoex-autowx.py index d6e199a..f285c42 100755 --- a/infoex-autowx.py +++ b/infoex-autowx.py @@ -85,7 +85,7 @@ def setup_config(config): station = dict() station['provider'] = config['station']['type'] - if station['provider'] not in ['nrcs', 'mesowest']: + if station['provider'] not in ['nrcs', 'mesowest', 'python']: print("Please specify either nrcs or mesowest as the station type.") sys.exit(1) @@ -112,6 +112,9 @@ def setup_config(config): '&stid=' + station['station_id'] + \ '&vars=' + station['desired_data'] + if station['provider'] == 'python': + station['path'] = config['station']['path'] + except KeyError as err: LOG.critical("%s not defined in configuration file", err) sys.exit(1) @@ -184,14 +187,23 @@ def main(): iemap = setup_infoex_counterparts_mapping(station['provider']) # override units if user selected metric - if station['units'] == 'metric': - final_data = switch_units_to_metric(final_data, fmap) + try: + if station['units'] == 'metric': + final_data = switch_units_to_metric(final_data, fmap) + except KeyError: + if station['provider'] != 'python': + LOG.error("Please specify the units in the configuration " + "file") + sys.exit(1) (begin_date, end_date) = setup_time_values() - # get the data - LOG.debug("Getting %s data from %s to %s", str(station['desired_data']), - str(begin_date), str(end_date)) + if station['provider'] == 'python': + LOG.debug("Getting custom data from external Python program") + else: + LOG.debug("Getting %s data from %s to %s", + str(station['desired_data']), + str(begin_date), str(end_date)) time_all_elements = time.time() @@ -201,6 +213,34 @@ def main(): elif station['provider'] == 'mesowest': infoex['wx_data'] = get_mesowest_data(begin_date, end_date, station) + elif station['provider'] == 'python': + try: + import importlib.util + + spec = importlib.util.spec_from_file_location('custom_wx', + station['path']) + mod = importlib.util.module_from_spec(spec) + spec.loader.exec_module(mod) + mod.LOG = LOG + + try: + infoex['wx_data'] = mod.get_custom_data() + + if infoex['wx_data'] is None: + infoex['wx_data'] = [] + except Exception: + LOG.error("Python program for custom Wx data failed in " + "execution") + sys.exit(1) + + LOG.info("Successfully executed external Python program") + except ImportError: + LOG.error("Please upgrade to Python 3.3 or later") + sys.exit(1) + except FileNotFoundError: + LOG.error("Specified Python program for custom Wx data " + "was not found") + sys.exit(1) LOG.info("Time taken to get all data : %.3f sec", time.time() - time_all_elements) @@ -245,13 +285,14 @@ def main(): LOG.debug("final_data: %s", str(final_data)) - if not write_local_csv(infoex['csv_filename'], final_data): - LOG.warning('Could not write local CSV file: %s', - infoex['csv_filename']) - return 1 + if len(infoex['wx_data']) > 0: + if not write_local_csv(infoex['csv_filename'], final_data): + LOG.warning('Could not write local CSV file: %s', + infoex['csv_filename']) + return 1 - if not options.dry_run: - upload_csv(infoex['csv_filename'], infoex) + if not options.dry_run: + upload_csv(infoex['csv_filename'], infoex) LOG.debug('DONE') return 0 @@ -336,6 +377,18 @@ def setup_infoex_counterparts_mapping(provider): iemap['wind_speed'] = 'windSpeedNum' iemap['wind_direction'] = 'windDirectionNum' iemap['wind_gust'] = 'windGustSpeedNum' + elif provider == 'python': + # we expect Python programs to use the InfoEx data type names + iemap['precipitationGauge'] = 'precipitationGauge' + iemap['tempPres'] = 'tempPres' + iemap['tempMaxHour'] = 'tempMaxHour' + iemap['tempMinHour'] = 'tempMinHour' + iemap['hS'] = 'hS' + iemap['baro'] = 'baro' + iemap['rH'] = 'rH' + iemap['windSpeedNum'] = 'windSpeedNum' + iemap['windDirectionNum'] = 'windDirectionNum' + iemap['windGustSpeedNum'] = 'windGustSpeedNum' return iemap