1
0
mirror of https://github.com/craigerl/aprsd.git synced 2024-12-22 09:31:42 -05:00

Added BeaconPacket

This patch adds the BeaconPacket and BeaconSendThread.
This will enable APRSD server to send a beacon if enabled in
the config.
This commit is contained in:
Hemna 2024-02-25 14:19:30 -05:00
parent 275bf67b9e
commit 11f1e9533e
7 changed files with 89 additions and 10 deletions

View File

@ -1,9 +1,8 @@
import click
from functools import update_wrapper from functools import update_wrapper
import logging import logging
from pathlib import Path from pathlib import Path
import typing as t import typing as t
import click
from oslo_config import cfg from oslo_config import cfg
import aprsd import aprsd
@ -50,9 +49,6 @@ common_options = [
] ]
import click
class AliasedGroup(click.Group): class AliasedGroup(click.Group):
def command(self, *args, **kwargs): def command(self, *args, **kwargs):
"""A shortcut decorator for declaring and attaching a command to """A shortcut decorator for declaring and attaching a command to

View File

@ -11,7 +11,7 @@ from aprsd import main as aprsd_main
from aprsd import packets, plugin, threads, utils from aprsd import packets, plugin, threads, utils
from aprsd.main import cli from aprsd.main import cli
from aprsd.rpc import server as rpc_server from aprsd.rpc import server as rpc_server
from aprsd.threads import rx from aprsd.threads import rx, tx
CONF = cfg.CONF CONF = cfg.CONF
@ -107,6 +107,10 @@ def server(ctx, flush):
process_thread.start() process_thread.start()
packets.PacketTrack().restart() packets.PacketTrack().restart()
if CONF.enable_beacon:
LOG.info("Beacon Enabled. Starting Beacon thread.")
bcn_thread = tx.BeaconSendThread()
bcn_thread.start()
if CONF.rpc_settings.enabled: if CONF.rpc_settings.enabled:
rpc = rpc_server.APRSDRPCThread() rpc = rpc_server.APRSDRPCThread()

View File

@ -70,6 +70,32 @@ aprsd_opts = [
default=60, default=60,
help="The number of seconds before a packet is not considered a duplicate.", help="The number of seconds before a packet is not considered a duplicate.",
), ),
cfg.BoolOpt(
"enable_beacon",
default=False,
help="Enable sending of a GPS Beacon packet to locate this service. "
"Requires latitude and longitude to be set.",
),
cfg.IntOpt(
"beacon_interval",
default=600,
help="The number of seconds between beacon packets.",
),
cfg.StrOpt(
"beacon_symbol",
default="/",
help="The symbol to use for the GPS Beacon packet. See: http://www.aprs.net/vm/DOS/SYMBOLS.HTM",
),
cfg.StrOpt(
"latitude",
default=None,
help="Latitude for the GPS Beacon button. If not set, the button will not be enabled.",
),
cfg.StrOpt(
"longitude",
default=None,
help="Longitude for the GPS Beacon button. If not set, the button will not be enabled.",
),
] ]
watch_list_opts = [ watch_list_opts = [

View File

@ -1,6 +1,6 @@
from aprsd.packets.core import ( # noqa: F401 from aprsd.packets.core import ( # noqa: F401
AckPacket, GPSPacket, MessagePacket, MicEPacket, Packet, RejectPacket, AckPacket, BeaconPacket, GPSPacket, MessagePacket, MicEPacket, Packet,
StatusPacket, WeatherPacket, RejectPacket, StatusPacket, WeatherPacket,
) )
from aprsd.packets.packet_list import PacketList # noqa: F401 from aprsd.packets.packet_list import PacketList # noqa: F401
from aprsd.packets.seen_list import SeenList # noqa: F401 from aprsd.packets.seen_list import SeenList # noqa: F401

View File

@ -466,6 +466,26 @@ class GPSPacket(Packet):
) )
@dataclass(unsafe_hash=True)
class BeaconPacket(GPSPacket):
def _build_payload(self):
"""The payload is the non headers portion of the packet."""
time_zulu = self._build_time_zulu()
lat = self.convert_latitude(self.latitude)
long = self.convert_longitude(self.longitude)
self.payload = (
f"@{time_zulu}z{lat}{self.symbol_table}"
f"{long}{self.symbol}APRSD Beacon"
)
def _build_raw(self):
self.raw = (
f"{self.from_call}>APZ100:"
f"{self.payload}"
)
@dataclass @dataclass
class MicEPacket(GPSPacket): class MicEPacket(GPSPacket):
messagecapable: bool = False messagecapable: bool = False

View File

@ -37,7 +37,6 @@ msg_throttle_decorator = decorator.ThrottleDecorator(throttle=msg_t)
ack_throttle_decorator = decorator.ThrottleDecorator(throttle=ack_t) ack_throttle_decorator = decorator.ThrottleDecorator(throttle=ack_t)
@msg_throttle_decorator.sleep_and_retry @msg_throttle_decorator.sleep_and_retry
def send(packet: core.Packet, direct=False, aprs_client=None): def send(packet: core.Packet, direct=False, aprs_client=None):
"""Send a packet either in a thread or directly to the client.""" """Send a packet either in a thread or directly to the client."""
@ -196,3 +195,38 @@ class SendAckThread(aprsd_threads.APRSDThread):
time.sleep(1) time.sleep(1)
self.loop_count += 1 self.loop_count += 1
return True return True
class BeaconSendThread(aprsd_threads.APRSDThread):
"""Thread that sends a GPS beacon packet periodically.
Settings are in the [DEFAULT] section of the config file.
"""
_loop_cnt: int = 1
def __init__(self):
super().__init__("BeaconSendThread")
self._loop_cnt = 1
# Make sure Latitude and Longitude are set.
if not CONF.latitude or not CONF.longitude:
LOG.error(
"Latitude and Longitude are not set in the config file."
"Beacon will not be sent and thread is STOPPED.",
)
self.stop()
def loop(self):
# Only dump out the stats every N seconds
if self._loop_cnt % CONF.beacon_interval == 0:
pkt = core.BeaconPacket(
from_call=CONF.callsign,
to_call="APRS",
latitude=float(CONF.latitude),
longitude=float(CONF.longitude),
comment="APRSD GPS Beacon",
symbol=CONF.beacon_symbol,
)
send(pkt, direct=True)
self._loop_cnt += 1
time.sleep(1)
return True

View File

@ -99,7 +99,6 @@ class ObjectStoreMixin:
LOG.debug( LOG.debug(
f"{self.__class__.__name__}::Loaded {len(self)} entries from disk.", f"{self.__class__.__name__}::Loaded {len(self)} entries from disk.",
) )
#LOG.debug(f"{self.data}")
else: else:
LOG.debug(f"{self.__class__.__name__}::No data to load.") LOG.debug(f"{self.__class__.__name__}::No data to load.")
except (pickle.UnpicklingError, Exception) as ex: except (pickle.UnpicklingError, Exception) as ex: