def command(self, fromcall, message, ack): api_key = self.config["services"]["aprs.fi"]["apiKey"] try: aprs_data = plugin_utils.get_aprs_fi(api_key, fromcall) except Exception as ex: LOG.error("Failed to fetch aprs.fi data {}".format(ex)) return "Failed to fetch location" # LOG.debug("LocationPlugin: aprs_data = {}".format(aprs_data)) lat = aprs_data["entries"][0]["lat"] lon = aprs_data["entries"][0]["lng"] try: utils.check_config_option( self.config, ["services", "openweathermap", "apiKey"], ) except Exception as ex: LOG.error("Failed to find config openweathermap:apiKey {}".format(ex)) return "No openweathermap apiKey found" api_key = self.config["services"]["openweathermap"]["apiKey"] try: results = plugin_utils.fetch_openweathermap(api_key, lat, lon) except Exception as ex: LOG.error("Couldn't fetch openweathermap api '{}'".format(ex)) # default to UTC localzone = pytz.timezone("UTC") else: tzone = results["timezone"] localzone = pytz.timezone(tzone) return self.build_date_str(localzone)
def command(self, fromcall, message, ack): api_key = self.config["services"]["aprs.fi"]["apiKey"] try: aprs_data = plugin_utils.get_aprs_fi(api_key, fromcall) except Exception as ex: LOG.error("Failed to fetch aprs.fi data {}".format(ex)) return "Failed to fetch location" # LOG.debug("LocationPlugin: aprs_data = {}".format(aprs_data)) lat = aprs_data["entries"][0]["lat"] lon = aprs_data["entries"][0]["lng"] try: utils.check_config_option(self.config, "opencagedata", "apiKey") except Exception as ex: LOG.error("Failed to find config opencage:apiKey {}".format(ex)) return "No opencage apiKey found" try: opencage_key = self.config["opencagedata"]["apiKey"] geocoder = OpenCageGeocode(opencage_key) results = geocoder.reverse_geocode(lat, lon) except Exception as ex: LOG.error("Couldn't fetch opencagedata api '{}'".format(ex)) # Default to UTC instead localzone = pytz.timezone("UTC") else: tzone = results[0]["annotations"]["timezone"]["name"] localzone = pytz.timezone(tzone) return self.build_date_str(localzone)
def command(self, fromcall, message, ack): LOG.info("Weather Plugin") try: utils.check_config_option(self.config, ["services", "aprs.fi", "apiKey"]) except Exception as ex: LOG.error("Failed to find config aprs.fi:apikey {}".format(ex)) return "No aprs.fi apikey found" api_key = self.config["services"]["aprs.fi"]["apiKey"] try: aprs_data = plugin_utils.get_aprs_fi(api_key, fromcall) except Exception as ex: LOG.error("Failed to fetch aprs.fi data {}".format(ex)) return "Failed to fetch location" # LOG.debug("LocationPlugin: aprs_data = {}".format(aprs_data)) lat = aprs_data["entries"][0]["lat"] lon = aprs_data["entries"][0]["lng"] try: wx_data = plugin_utils.get_weather_gov_for_gps(lat, lon) except Exception as ex: LOG.error("Couldn't fetch forecast.weather.gov '{}'".format(ex)) return "Unable to get weather" reply = ( "%sF(%sF/%sF) %s. %s, %s." % ( wx_data["currentobservation"]["Temp"], wx_data["data"]["temperature"][0], wx_data["data"]["temperature"][1], wx_data["data"]["weather"][0], wx_data["time"]["startPeriodName"][1], wx_data["data"]["weather"][1], ) ).rstrip() LOG.debug("reply: '{}' ".format(reply)) return reply
def command(self, fromcall, message, ack): LOG.info("Location Plugin") # get last location of a callsign, get descriptive name from weather service try: utils.check_config_option(self.config, ["services", "aprs.fi", "apiKey"]) except Exception as ex: LOG.error("Failed to find config aprs.fi:apikey {}".format(ex)) return "No aprs.fi apikey found" api_key = self.config["services"]["aprs.fi"]["apiKey"] # optional second argument is a callsign to search a = re.search(r"^.*\s+(.*)", message) if a is not None: searchcall = a.group(1) searchcall = searchcall.upper() else: # if no second argument, search for calling station searchcall = fromcall try: aprs_data = plugin_utils.get_aprs_fi(api_key, searchcall) except Exception as ex: LOG.error("Failed to fetch aprs.fi '{}'".format(ex)) return "Failed to fetch aprs.fi location" LOG.debug("LocationPlugin: aprs_data = {}".format(aprs_data)) if not len(aprs_data["entries"]): LOG.error("Didn't get any entries from aprs.fi") return "Failed to fetch aprs.fi location" lat = aprs_data["entries"][0]["lat"] lon = aprs_data["entries"][0]["lng"] try: # altitude not always provided alt = float(aprs_data["entries"][0]["altitude"]) except Exception: alt = 0 altfeet = int(alt * 3.28084) aprs_lasttime_seconds = aprs_data["entries"][0]["lasttime"] # aprs_lasttime_seconds = aprs_lasttime_seconds.encode( # "ascii", errors="ignore" # ) # unicode to ascii delta_seconds = time.time() - int(aprs_lasttime_seconds) delta_hours = delta_seconds / 60 / 60 try: wx_data = plugin_utils.get_weather_gov_for_gps(lat, lon) except Exception as ex: LOG.error("Couldn't fetch forecast.weather.gov '{}'".format(ex)) wx_data = {"location": {"areaDescription": "Unknown Location"}} if "location" not in wx_data: LOG.error( "Couldn't fetch forecast.weather.gov '{}'".format(wx_data)) wx_data = {"location": {"areaDescription": "Unknown Location"}} reply = "{}: {} {}' {},{} {}h ago".format( searchcall, wx_data["location"]["areaDescription"], str(altfeet), str(lat), str(lon), str("%.1f" % round(delta_hours, 1)), ).rstrip() return reply
def command(self, fromcall, message, ack): LOG.info("WX Plugin '{}'".format(message)) a = re.search(r"^.*\s+(.*)", message) if a is not None: searchcall = a.group(1) station = searchcall.upper() try: resp = plugin_utils.get_weather_gov_metar(station) except Exception as e: LOG.debug("Weather failed with: {}".format(str(e))) reply = "Unable to find station METAR" else: station_data = json.loads(resp.text) reply = station_data["properties"]["rawMessage"] return reply else: # if no second argument, search for calling station fromcall = fromcall try: utils.check_config_option( self.config, ["services", "aprs.fi", "apiKey"], ) except Exception as ex: LOG.error("Failed to find config aprs.fi:apikey {}".format(ex)) return "No aprs.fi apikey found" api_key = self.config["services"]["aprs.fi"]["apiKey"] try: aprs_data = plugin_utils.get_aprs_fi(api_key, fromcall) except Exception as ex: LOG.error("Failed to fetch aprs.fi data {}".format(ex)) return "Failed to fetch location" # LOG.debug("LocationPlugin: aprs_data = {}".format(aprs_data)) if not len(aprs_data["entries"]): LOG.error("Found no entries from aprs.fi!") return "Failed to fetch location" lat = aprs_data["entries"][0]["lat"] lon = aprs_data["entries"][0]["lng"] try: wx_data = plugin_utils.get_weather_gov_for_gps(lat, lon) except Exception as ex: LOG.error("Couldn't fetch forecast.weather.gov '{}'".format(ex)) return "Unable to metar find station." if wx_data["location"]["metar"]: station = wx_data["location"]["metar"] try: resp = plugin_utils.get_weather_gov_metar(station) except Exception as e: LOG.debug("Weather failed with: {}".format(str(e))) reply = "Failed to get Metar" else: station_data = json.loads(resp.text) reply = station_data["properties"]["rawMessage"] else: # Couldn't find a station reply = "No Metar station found" return reply
def command(self, fromcall, message, ack): LOG.info("OWMWeather Plugin '{}'".format(message)) a = re.search(r"^.*\s+(.*)", message) if a is not None: searchcall = a.group(1) searchcall = searchcall.upper() else: searchcall = fromcall try: utils.check_config_option(self.config, ["services", "aprs.fi", "apiKey"]) except Exception as ex: LOG.error("Failed to find config aprs.fi:apikey {}".format(ex)) return "No aprs.fi apikey found" api_key = self.config["services"]["aprs.fi"]["apiKey"] try: aprs_data = plugin_utils.get_aprs_fi(api_key, searchcall) except Exception as ex: LOG.error("Failed to fetch aprs.fi data {}".format(ex)) return "Failed to fetch location" # LOG.debug("LocationPlugin: aprs_data = {}".format(aprs_data)) if not len(aprs_data["entries"]): LOG.error("Found no entries from aprs.fi!") return "Failed to fetch location" lat = aprs_data["entries"][0]["lat"] lon = aprs_data["entries"][0]["lng"] try: utils.check_config_option(self.config, ["services", "avwx", "apiKey"]) except Exception as ex: LOG.error("Failed to find config avwx:apiKey {}".format(ex)) return "No avwx apiKey found" try: utils.check_config_option(self.config, ["services", "avwx", "base_url"]) except Exception as ex: LOG.debut("Didn't find avwx:base_url {}".format(ex)) base_url = "https://avwx.rest" else: base_url = self.config["services"]["avwx"]["base_url"] api_key = self.config["services"]["avwx"]["apiKey"] token = "TOKEN {}".format(api_key) headers = {"Authorization": token} try: coord = "{},{}".format(lat, lon) url = ( "{}/api/station/near/{}?" "n=1&airport=false&reporting=true&format=json".format(base_url, coord) ) LOG.debug("Get stations near me '{}'".format(url)) response = requests.get(url, headers=headers) except Exception as ex: LOG.error(ex) raise Exception("Failed to get the weather '{}'".format(ex)) else: wx_data = json.loads(response.text) # LOG.debug(wx_data) station = wx_data[0]["station"]["icao"] try: url = ( "{}/api/metar/{}?options=info,translate,summary" "&airport=true&reporting=true&format=json&onfail=cache".format( base_url, station, ) ) LOG.debug("Get METAR '{}'".format(url)) response = requests.get(url, headers=headers) except Exception as ex: LOG.error(ex) raise Exception("Failed to get metar {}".format(ex)) else: metar_data = json.loads(response.text) # LOG.debug(metar_data) return metar_data["raw"]
def command(self, fromcall, message, ack): LOG.info("OWMWeather Plugin '{}'".format(message)) a = re.search(r"^.*\s+(.*)", message) if a is not None: searchcall = a.group(1) searchcall = searchcall.upper() else: searchcall = fromcall try: utils.check_config_option(self.config, ["services", "aprs.fi", "apiKey"]) except Exception as ex: LOG.error("Failed to find config aprs.fi:apikey {}".format(ex)) return "No aprs.fi apikey found" api_key = self.config["services"]["aprs.fi"]["apiKey"] try: aprs_data = plugin_utils.get_aprs_fi(api_key, searchcall) except Exception as ex: LOG.error("Failed to fetch aprs.fi data {}".format(ex)) return "Failed to fetch location" # LOG.debug("LocationPlugin: aprs_data = {}".format(aprs_data)) if not len(aprs_data["entries"]): LOG.error("Found no entries from aprs.fi!") return "Failed to fetch location" lat = aprs_data["entries"][0]["lat"] lon = aprs_data["entries"][0]["lng"] try: utils.check_config_option( self.config, ["services", "openweathermap", "apiKey"], ) except Exception as ex: LOG.error("Failed to find config openweathermap:apiKey {}".format(ex)) return "No openweathermap apiKey found" try: utils.check_config_option(self.config, ["aprsd", "units"]) except Exception: LOG.debug("Couldn't find untis in aprsd:services:units") units = "metric" else: units = self.config["aprsd"]["units"] api_key = self.config["services"]["openweathermap"]["apiKey"] try: wx_data = plugin_utils.fetch_openweathermap( api_key, lat, lon, units=units, exclude="minutely,hourly", ) except Exception as ex: LOG.error("Couldn't fetch openweathermap api '{}'".format(ex)) # default to UTC return "Unable to get weather" if units == "metric": degree = "C" else: degree = "F" if "wind_gust" in wx_data["current"]: wind = "{:.0f}@{}G{:.0f}".format( wx_data["current"]["wind_speed"], wx_data["current"]["wind_deg"], wx_data["current"]["wind_gust"], ) else: wind = "{:.0f}@{}".format( wx_data["current"]["wind_speed"], wx_data["current"]["wind_deg"], ) # LOG.debug(wx_data["current"]) # LOG.debug(wx_data["daily"]) reply = "{} {:.1f}{}/{:.1f}{} Wind {} {}%".format( wx_data["current"]["weather"][0]["description"], wx_data["current"]["temp"], degree, wx_data["current"]["dew_point"], degree, wind, wx_data["current"]["humidity"], ) return reply
def server( loglevel, quiet, disable_validation, config_file, flush, ): """Start the aprsd server process.""" global flask_enabled signal.signal(signal.SIGINT, signal_handler) if not quiet: click.echo("Load config") config = utils.parse_config(config_file) # Force setting the config to the modules that need it # TODO(Walt): convert these modules to classes that can # Accept the config as a constructor param, instead of this # hacky global setting email.CONFIG = config setup_logging(config, loglevel, quiet) if config["aprsd"].get("trace", False): trace.setup_tracing(["method", "api"]) LOG.info("APRSD Started version: {}".format(aprsd.__version__)) stats.APRSDStats(config) email_enabled = config["aprsd"]["email"].get("enabled", False) if email_enabled: # TODO(walt): Make email processing/checking optional? # Maybe someone only wants this to process messages with plugins only. valid = email.validate_email_config(config, disable_validation) if not valid: LOG.error("Failed to validate email config options") sys.exit(-1) else: LOG.info("Email services not enabled.") # Create the initial PM singleton and Register plugins plugin_manager = plugin.PluginManager(config) plugin_manager.setup_plugins() try: cl = client.Client(config) cl.client except LoginError: sys.exit(-1) # Now load the msgTrack from disk if any if flush: LOG.debug("Deleting saved MsgTrack.") messaging.MsgTrack().flush() else: # Try and load saved MsgTrack list LOG.debug("Loading saved MsgTrack object.") messaging.MsgTrack().load() rx_msg_queue = queue.Queue(maxsize=20) tx_msg_queue = queue.Queue(maxsize=20) msg_queues = {"rx": rx_msg_queue, "tx": tx_msg_queue} rx_thread = threads.APRSDRXThread(msg_queues=msg_queues, config=config) tx_thread = threads.APRSDTXThread(msg_queues=msg_queues, config=config) if email_enabled: email_thread = email.APRSDEmailThread(msg_queues=msg_queues, config=config) email_thread.start() rx_thread.start() tx_thread.start() messaging.MsgTrack().restart() keepalive = threads.KeepAliveThread() keepalive.start() try: web_enabled = utils.check_config_option(config, ["aprsd", "web", "enabled"]) except Exception: web_enabled = False if web_enabled: flask_enabled = True app = flask.init_flask(config) app.run( host=config["aprsd"]["web"]["host"], port=config["aprsd"]["web"]["port"], ) # If there are items in the msgTracker, then save them LOG.info("APRSD Exiting.") return 0