Beispiel #1
0
    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)
Beispiel #2
0
    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)
Beispiel #3
0
    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
Beispiel #4
0
    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
Beispiel #5
0
    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
Beispiel #6
0
    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"]
Beispiel #7
0
    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
Beispiel #8
0
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