mirror of
https://github.com/craigerl/aprsd.git
synced 2024-11-24 08:58:49 -05:00
Compare commits
8 Commits
6a5250ad1d
...
4313fb8940
Author | SHA1 | Date | |
---|---|---|---|
|
4313fb8940 | ||
8cdbf18bef | |||
a65262d2ff | |||
9951b12e2d | |||
3e9bf2422a | |||
5e9f92dfa6 | |||
5314856101 | |||
|
1334eded62 |
2
Makefile
2
Makefile
@ -24,7 +24,7 @@ run: venv ## Create a virtual environment for running aprsd commands
|
||||
|
||||
changelog: dev
|
||||
npm i -g auto-changelog
|
||||
auto-changelog -l false -o ChangeLog.md
|
||||
auto-changelog -l false --sort-commits date -o ChangeLog.md
|
||||
|
||||
docs: changelog
|
||||
m2r --overwrite ChangeLog.md
|
||||
|
@ -33,7 +33,11 @@ class Aprsdis(aprslib.IS):
|
||||
|
||||
def stop(self):
|
||||
self.thread_stop = True
|
||||
LOG.info("Shutdown Aprsdis client.")
|
||||
LOG.warning("Shutdown Aprsdis client.")
|
||||
|
||||
def close(self):
|
||||
LOG.warning("Closing Aprsdis client.")
|
||||
super().close()
|
||||
|
||||
@wrapt.synchronized(lock)
|
||||
def send(self, packet: core.Packet):
|
||||
|
@ -42,7 +42,8 @@ def signal_handler(sig, frame):
|
||||
),
|
||||
)
|
||||
time.sleep(5)
|
||||
LOG.info(collector.Collector().collect())
|
||||
# Last save to disk
|
||||
collector.Collector().collect()
|
||||
|
||||
|
||||
class APRSDListenThread(rx.APRSDRXThread):
|
||||
|
@ -64,7 +64,7 @@ def signal_handler(sig, frame):
|
||||
time.sleep(1.5)
|
||||
# packets.WatchList().save()
|
||||
# packets.SeenList().save()
|
||||
LOG.info(stats.stats_collector.collect())
|
||||
stats.stats_collector.collect()
|
||||
LOG.info("Telling flask to bail.")
|
||||
signal.signal(signal.SIGTERM, sys.exit(0))
|
||||
|
||||
|
@ -136,6 +136,11 @@ aprsd_opts = [
|
||||
default=True,
|
||||
help="Set this to False, to disable logging of packets to the log file.",
|
||||
),
|
||||
cfg.BoolOpt(
|
||||
"load_help_plugin",
|
||||
default=True,
|
||||
help="Set this to False to disable the help plugin.",
|
||||
),
|
||||
]
|
||||
|
||||
watch_list_opts = [
|
||||
|
@ -83,7 +83,7 @@ def signal_handler(sig, frame):
|
||||
packets.WatchList().save()
|
||||
packets.SeenList().save()
|
||||
packets.PacketList().save()
|
||||
LOG.info(collector.Collector().collect())
|
||||
collector.Collector().collect()
|
||||
# signal.signal(signal.SIGTERM, sys.exit(0))
|
||||
# sys.exit(0)
|
||||
|
||||
|
@ -1,10 +1,12 @@
|
||||
import logging
|
||||
from typing import Optional
|
||||
|
||||
from geopy.distance import geodesic
|
||||
from loguru import logger
|
||||
from oslo_config import cfg
|
||||
|
||||
from aprsd.packets.core import AckPacket, RejectPacket
|
||||
from aprsd import utils
|
||||
from aprsd.packets.core import AckPacket, GPSPacket, RejectPacket
|
||||
|
||||
|
||||
LOG = logging.getLogger()
|
||||
@ -16,6 +18,8 @@ TO_COLOR = "fg #D033FF"
|
||||
TX_COLOR = "red"
|
||||
RX_COLOR = "green"
|
||||
PACKET_COLOR = "cyan"
|
||||
DISTANCE_COLOR = "fg #FF5733"
|
||||
DEGREES_COLOR = "fg #FFA900"
|
||||
|
||||
|
||||
def log_multiline(packet, tx: Optional[bool] = False, header: Optional[bool] = True) -> None:
|
||||
@ -97,19 +101,21 @@ def log(packet, tx: Optional[bool] = False, header: Optional[bool] = True) -> No
|
||||
if header:
|
||||
if tx:
|
||||
via_color = "red"
|
||||
arrow = f"<{via_color}>-></{via_color}>"
|
||||
# arrow = f"<{via_color}>-></{via_color}>"
|
||||
arrow = f"<{via_color}>\u2192</{via_color}>"
|
||||
logit.append(
|
||||
f"<red>TX {arrow}</red> "
|
||||
f"<red>TX\u2191</red> "
|
||||
f"<cyan>{name}</cyan>"
|
||||
f":{packet.msgNo}"
|
||||
f" ({packet.send_count + 1} of {pkt_max_send_count})",
|
||||
)
|
||||
else:
|
||||
via_color = "fg #828282"
|
||||
arrow = f"<{via_color}>-></{via_color}>"
|
||||
left_arrow = f"<{via_color}><-</{via_color}>"
|
||||
via_color = "fg #1AA730"
|
||||
#arrow = f"<{via_color}>-></{via_color}>"
|
||||
arrow = f"<{via_color}>\u2192</{via_color}>"
|
||||
f"<{via_color}><-</{via_color}>"
|
||||
logit.append(
|
||||
f"<fg #1AA730>RX</fg #1AA730> {left_arrow} "
|
||||
f"<fg #1AA730>RX\u2193</fg #1AA730> "
|
||||
f"<cyan>{name}</cyan>"
|
||||
f":{packet.msgNo}",
|
||||
)
|
||||
@ -139,5 +145,19 @@ def log(packet, tx: Optional[bool] = False, header: Optional[bool] = True) -> No
|
||||
msg = msg.replace("<", "\\<")
|
||||
logit.append(f"<light-yellow><b>{msg}</b></light-yellow>")
|
||||
|
||||
# is there distance information?
|
||||
if isinstance(packet, GPSPacket) and CONF.latitude and CONF.longitude:
|
||||
my_coords = (CONF.latitude, CONF.longitude)
|
||||
packet_coords = (packet.latitude, packet.longitude)
|
||||
try:
|
||||
bearing = utils.calculate_initial_compass_bearing(my_coords, packet_coords)
|
||||
except Exception as e:
|
||||
LOG.error(f"Failed to calculate bearing: {e}")
|
||||
bearing = 0
|
||||
logit.append(
|
||||
f" : <{DEGREES_COLOR}>{utils.degrees_to_cardinal(bearing, full_string=True)}</{DEGREES_COLOR}>"
|
||||
f"<{DISTANCE_COLOR}>@{geodesic(my_coords, packet_coords).miles:.2f}miles</{DISTANCE_COLOR}>",
|
||||
)
|
||||
|
||||
LOGU.opt(colors=True).info(" ".join(logit))
|
||||
log_multiline(packet, tx, header)
|
||||
|
@ -472,9 +472,13 @@ class PluginManager:
|
||||
del self._pluggy_pm
|
||||
self.setup_plugins()
|
||||
|
||||
def setup_plugins(self, load_help_plugin=True):
|
||||
def setup_plugins(self, load_help_plugin=None):
|
||||
"""Create the plugin manager and register plugins."""
|
||||
|
||||
# If load_help_plugin is not specified, load it from the config
|
||||
if load_help_plugin is None:
|
||||
load_help_plugin = CONF.load_help_plugin
|
||||
|
||||
LOG.info("Loading APRSD Plugins")
|
||||
# Help plugin is always enabled.
|
||||
if load_help_plugin:
|
||||
|
@ -3,6 +3,7 @@ import logging
|
||||
import time
|
||||
import tracemalloc
|
||||
|
||||
from loguru import logger
|
||||
from oslo_config import cfg
|
||||
|
||||
from aprsd import packets, utils
|
||||
@ -14,6 +15,7 @@ from aprsd.threads import APRSDThread, APRSDThreadList
|
||||
|
||||
CONF = cfg.CONF
|
||||
LOG = logging.getLogger("APRSD")
|
||||
LOGU = logger
|
||||
|
||||
|
||||
class KeepAliveThread(APRSDThread):
|
||||
@ -87,7 +89,12 @@ class KeepAliveThread(APRSDThread):
|
||||
key = thread["name"]
|
||||
if not alive:
|
||||
LOG.error(f"Thread {thread}")
|
||||
LOG.info(f"{key: <15} Alive? {str(alive): <5} {str(age): <20}")
|
||||
|
||||
thread_hex = f"fg {utils.hex_from_name(key)}"
|
||||
t_name = f"<{thread_hex}>{key:<15}</{thread_hex}>"
|
||||
thread_msg = f"{t_name} Alive? {str(alive): <5} {str(age): <20}"
|
||||
LOGU.opt(colors=True).info(thread_msg)
|
||||
# LOG.info(f"{key: <15} Alive? {str(alive): <5} {str(age): <20}")
|
||||
|
||||
# check the APRS connection
|
||||
cl = client_factory.create()
|
||||
|
@ -328,8 +328,22 @@ class APRSDPluginProcessPacketThread(APRSDProcessPacketThread):
|
||||
# If the message was for us and we didn't have a
|
||||
# response, then we send a usage statement.
|
||||
if to_call == CONF.callsign and not replied:
|
||||
LOG.warning("Sending help!")
|
||||
message_text = "Unknown command! Send 'help' message for help"
|
||||
|
||||
# Is the help plugin installed?
|
||||
help_available = False
|
||||
for p in pm.get_message_plugins():
|
||||
if isinstance(p, plugin.HelpPlugin):
|
||||
help_available = True
|
||||
break
|
||||
|
||||
# Tailor the messages accordingly
|
||||
if help_available:
|
||||
LOG.warning("Sending help!")
|
||||
message_text = "Unknown command! Send 'help' message for help"
|
||||
else:
|
||||
LOG.warning("Unknown command!")
|
||||
message_text = "Unknown command!"
|
||||
|
||||
tx.send(
|
||||
packets.MessagePacket(
|
||||
from_call=CONF.callsign,
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
import errno
|
||||
import functools
|
||||
import math
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
@ -82,6 +83,16 @@ def rgb_from_name(name):
|
||||
return red, green, blue
|
||||
|
||||
|
||||
def hextriplet(colortuple):
|
||||
"""Convert a color tuple to a hex triplet."""
|
||||
return "#" + "".join(f"{i:02X}" for i in colortuple)
|
||||
|
||||
|
||||
def hex_from_name(name):
|
||||
"""Create a hex color from a string."""
|
||||
return hextriplet(rgb_from_name(name))
|
||||
|
||||
|
||||
def human_size(bytes, units=None):
|
||||
"""Returns a human readable string representation of bytes"""
|
||||
if not units:
|
||||
@ -161,3 +172,47 @@ def load_entry_points(group):
|
||||
except Exception as e:
|
||||
print(f"Extension {ep.name} of group {group} failed to load with {e}", file=sys.stderr)
|
||||
print(traceback.format_exc(), file=sys.stderr)
|
||||
|
||||
|
||||
def calculate_initial_compass_bearing(start, end):
|
||||
if (type(start) != tuple) or (type(end) != tuple):
|
||||
raise TypeError("Only tuples are supported as arguments")
|
||||
|
||||
lat1 = math.radians(float(start[0]))
|
||||
lat2 = math.radians(float(end[0]))
|
||||
|
||||
diffLong = math.radians(float(end[1]) - float(start[1]))
|
||||
|
||||
x = math.sin(diffLong) * math.cos(lat2)
|
||||
y = math.cos(lat1) * math.sin(lat2) - (
|
||||
math.sin(lat1)
|
||||
* math.cos(lat2) * math.cos(diffLong)
|
||||
)
|
||||
|
||||
initial_bearing = math.atan2(x, y)
|
||||
|
||||
# Now we have the initial bearing but math.atan2 return values
|
||||
# from -180° to + 180° which is not what we want for a compass bearing
|
||||
# The solution is to normalize the initial bearing as shown below
|
||||
initial_bearing = math.degrees(initial_bearing)
|
||||
compass_bearing = (initial_bearing + 360) % 360
|
||||
|
||||
return compass_bearing
|
||||
|
||||
|
||||
def degrees_to_cardinal(bearing, full_string=False):
|
||||
if full_string:
|
||||
DIRECTIONS = [
|
||||
"North", "North-Northeast", "Northeast", "East-Northeast", "East", "East-Southeast",
|
||||
"Southeast", "South-Southeast", "South", "South-Southwest", "Southwest", "West-Southwest",
|
||||
"West", "West-Northwest", "Northwest", "North-Northwest", "North",
|
||||
]
|
||||
else:
|
||||
DIRECTIONS = [
|
||||
"N", "NNE", "NE", "ENE", "E", "ESE",
|
||||
"SE", "SSE", "S", "SSW", "SW", "WSW",
|
||||
"W", "WNW", "NW", "NNW", "N",
|
||||
]
|
||||
|
||||
cardinal = DIRECTIONS[round(bearing / 22.5)]
|
||||
return cardinal
|
||||
|
@ -1,4 +1,4 @@
|
||||
FROM python:3.11-slim as build
|
||||
FROM python:3.11-slim AS build
|
||||
|
||||
ARG VERSION=3.4.0
|
||||
# pass this in as 'dev' if you want to install from github repo vs pypi
|
||||
@ -40,7 +40,7 @@ RUN set -ex \
|
||||
|
||||
|
||||
### Final stage
|
||||
FROM build as final
|
||||
FROM build AS install
|
||||
WORKDIR /app
|
||||
|
||||
RUN pip3 install -U pip
|
||||
@ -64,6 +64,8 @@ RUN aprsd --version
|
||||
ADD bin/setup.sh /app
|
||||
ADD bin/admin.sh /app
|
||||
|
||||
|
||||
FROM install AS final
|
||||
# For the web admin interface
|
||||
EXPOSE 8001
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user