aprsd/aprsd/plugins/time.py

183 lines
5.8 KiB
Python

import logging
import re
import time
from opencage.geocoder import OpenCageGeocode
import pytz
from aprsd import fuzzyclock, plugin, plugin_utils, trace, utils
LOG = logging.getLogger("APRSD")
class TimePlugin(plugin.APRSDMessagePluginBase):
"""Time command."""
version = "1.0"
command_regex = "^[tT]"
command_name = "time"
def _get_local_tz(self):
return pytz.timezone(time.strftime("%Z"))
def _get_utcnow(self):
return pytz.datetime.datetime.utcnow()
def build_date_str(self, localzone):
utcnow = self._get_utcnow()
gmt_t = pytz.utc.localize(utcnow)
local_t = gmt_t.astimezone(localzone)
local_short_str = local_t.strftime("%H:%M %Z")
local_hour = local_t.strftime("%H")
local_min = local_t.strftime("%M")
cur_time = fuzzyclock.fuzzy(int(local_hour), int(local_min), 1)
reply = "{} ({})".format(
cur_time,
local_short_str,
)
return reply
@trace.trace
def command(self, packet):
LOG.info("TIME COMMAND")
# So we can mock this in unit tests
localzone = self._get_local_tz()
return self.build_date_str(localzone)
class TimeOpenCageDataPlugin(TimePlugin):
"""geocage based timezone fetching."""
version = "1.0"
command_regex = "^[tT]"
command_name = "Time"
@trace.trace
def command(self, packet):
fromcall = packet.get("from")
message = packet.get("message_text", None)
# ack = packet.get("msgNo", "0")
# 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(f"Failed to find config aprs.fi:apikey {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(f"Failed to fetch aprs.fi data {ex}")
return "Failed to fetch 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:
utils.check_config_option(self.config, "opencagedata", "apiKey")
except Exception as ex:
LOG.error(f"Failed to find config opencage:apiKey {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(f"Couldn't fetch opencagedata api '{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)
class TimeOWMPlugin(TimePlugin):
"""OpenWeatherMap based timezone fetching."""
version = "1.0"
command_regex = "^[tT]"
command_name = "Time"
@trace.trace
def command(self, packet):
fromcall = packet.get("from")
message = packet.get("message_text", None)
# ack = packet.get("msgNo", "0")
# 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(f"Failed to find config aprs.fi:apikey {ex}")
return "No aprs.fi apikey found"
# 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
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(f"Failed to fetch aprs.fi data {ex}")
return "Failed to fetch location"
LOG.debug(f"LocationPlugin: aprs_data = {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:
utils.check_config_option(
self.config,
["services", "openweathermap", "apiKey"],
)
except Exception as ex:
LOG.error(f"Failed to find config openweathermap:apiKey {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(f"Couldn't fetch openweathermap api '{ex}'")
# default to UTC
localzone = pytz.timezone("UTC")
else:
tzone = results["timezone"]
localzone = pytz.timezone(tzone)
return self.build_date_str(localzone)