mirror of
https://github.com/craigerl/aprsd.git
synced 2025-04-10 05:28:58 -04:00
Merge pull request #50 from craigerl/tcpkiss
Added the ability to use direwolf KISS socket
This commit is contained in:
commit
d243e577f0
@ -90,6 +90,11 @@ class Aprsdis(aprslib.IS):
|
||||
self.thread_stop = True
|
||||
LOG.info("Shutdown Aprsdis client.")
|
||||
|
||||
def send(self, msg):
|
||||
"""Send an APRS Message object."""
|
||||
line = str(msg)
|
||||
self.sendall(line)
|
||||
|
||||
def _socket_readlines(self, blocking=False):
|
||||
"""
|
||||
Generator for complete lines, received from the server
|
||||
|
@ -11,7 +11,7 @@ from flask_httpauth import HTTPBasicAuth
|
||||
from werkzeug.security import check_password_hash, generate_password_hash
|
||||
|
||||
import aprsd
|
||||
from aprsd import messaging, packets, plugin, stats, utils
|
||||
from aprsd import kissclient, messaging, packets, plugin, stats, utils
|
||||
|
||||
|
||||
LOG = logging.getLogger("APRSD")
|
||||
@ -65,9 +65,38 @@ class APRSDFlask(flask_classful.FlaskView):
|
||||
plugins = pm.get_plugins()
|
||||
plugin_count = len(plugins)
|
||||
|
||||
if self.config["aprs"].get("enabled", True):
|
||||
transport = "aprs-is"
|
||||
aprs_connection = (
|
||||
"APRS-IS Server: <a href='http://status.aprs2.net' >"
|
||||
"{}</a>".format(stats["stats"]["aprs-is"]["server"])
|
||||
)
|
||||
else:
|
||||
# We might be connected to a KISS socket?
|
||||
if kissclient.KISSClient.kiss_enabled(self.config):
|
||||
transport = kissclient.KISSClient.transport(self.config)
|
||||
if transport == kissclient.TRANSPORT_TCPKISS:
|
||||
aprs_connection = (
|
||||
"TCPKISS://{}:{}".format(
|
||||
self.config["kiss"]["tcp"]["host"],
|
||||
self.config["kiss"]["tcp"]["port"],
|
||||
)
|
||||
)
|
||||
elif transport == kissclient.TRANSPORT_SERIALKISS:
|
||||
aprs_connection = (
|
||||
"SerialKISS://{}@{} baud".format(
|
||||
self.config["kiss"]["serial"]["device"],
|
||||
self.config["kiss"]["serial"]["baudrate"],
|
||||
)
|
||||
)
|
||||
|
||||
stats["transport"] = transport
|
||||
stats["aprs_connection"] = aprs_connection
|
||||
|
||||
return flask.render_template(
|
||||
"index.html",
|
||||
initial_stats=stats,
|
||||
aprs_connection=aprs_connection,
|
||||
callsign=self.config["aprs"]["login"],
|
||||
version=aprsd.__version__,
|
||||
config_json=json.dumps(self.config),
|
||||
|
152
aprsd/kissclient.py
Normal file
152
aprsd/kissclient.py
Normal file
@ -0,0 +1,152 @@
|
||||
import asyncio
|
||||
import logging
|
||||
|
||||
from aioax25 import interface
|
||||
from aioax25 import kiss as kiss
|
||||
from aioax25.aprs import APRSInterface
|
||||
|
||||
from aprsd import trace
|
||||
|
||||
|
||||
TRANSPORT_TCPKISS = "tcpkiss"
|
||||
TRANSPORT_SERIALKISS = "serialkiss"
|
||||
LOG = logging.getLogger("APRSD")
|
||||
|
||||
|
||||
class KISSClient:
|
||||
|
||||
_instance = None
|
||||
config = None
|
||||
ax25client = None
|
||||
loop = None
|
||||
|
||||
def __new__(cls, *args, **kwargs):
|
||||
"""Singleton for this class."""
|
||||
if cls._instance is None:
|
||||
cls._instance = super().__new__(cls)
|
||||
# initialize shit here
|
||||
return cls._instance
|
||||
|
||||
def __init__(self, config=None):
|
||||
if config:
|
||||
self.config = config
|
||||
|
||||
@staticmethod
|
||||
def kiss_enabled(config):
|
||||
"""Return if tcp or serial KISS is enabled."""
|
||||
if "kiss" not in config:
|
||||
return False
|
||||
|
||||
if "serial" in config["kiss"]:
|
||||
if config["kiss"]["serial"].get("enabled", False):
|
||||
return True
|
||||
|
||||
if "tcp" in config["kiss"]:
|
||||
if config["kiss"]["tcp"].get("enabled", False):
|
||||
return True
|
||||
|
||||
@staticmethod
|
||||
def transport(config):
|
||||
if "serial" in config["kiss"]:
|
||||
if config["kiss"]["serial"].get("enabled", False):
|
||||
return TRANSPORT_SERIALKISS
|
||||
|
||||
if "tcp" in config["kiss"]:
|
||||
if config["kiss"]["tcp"].get("enabled", False):
|
||||
return TRANSPORT_TCPKISS
|
||||
|
||||
@property
|
||||
def client(self):
|
||||
if not self.ax25client:
|
||||
self.ax25client = self.setup_connection()
|
||||
return self.ax25client
|
||||
|
||||
def reset(self):
|
||||
"""Call this to fore a rebuild/reconnect."""
|
||||
self.ax25client.stop()
|
||||
del self.ax25client
|
||||
|
||||
@trace.trace
|
||||
def setup_connection(self):
|
||||
ax25client = Aioax25Client(self.config)
|
||||
LOG.debug("Complete")
|
||||
return ax25client
|
||||
|
||||
|
||||
class Aioax25Client:
|
||||
def __init__(self, config):
|
||||
self.config = config
|
||||
self.setup()
|
||||
|
||||
def setup(self):
|
||||
# we can be TCP kiss or Serial kiss
|
||||
|
||||
self.loop = asyncio.get_event_loop()
|
||||
if "serial" in self.config["kiss"] and self.config["kiss"]["serial"].get(
|
||||
"enabled",
|
||||
False,
|
||||
):
|
||||
LOG.debug(
|
||||
"Setting up Serial KISS connection to {}".format(
|
||||
self.config["kiss"]["serial"]["device"],
|
||||
),
|
||||
)
|
||||
self.kissdev = kiss.SerialKISSDevice(
|
||||
device=self.config["kiss"]["serial"]["device"],
|
||||
baudrate=self.config["kiss"]["serial"].get("baudrate", 9600),
|
||||
loop=self.loop,
|
||||
)
|
||||
elif "tcp" in self.config["kiss"] and self.config["kiss"]["tcp"].get(
|
||||
"enabled",
|
||||
False,
|
||||
):
|
||||
LOG.debug(
|
||||
"Setting up KISSTCP Connection to {}:{}".format(
|
||||
self.config["kiss"]["tcp"]["host"],
|
||||
self.config["kiss"]["tcp"]["port"],
|
||||
),
|
||||
)
|
||||
self.kissdev = kiss.TCPKISSDevice(
|
||||
self.config["kiss"]["tcp"]["host"],
|
||||
self.config["kiss"]["tcp"]["port"],
|
||||
loop=self.loop,
|
||||
log=LOG,
|
||||
)
|
||||
|
||||
self.kissdev.open()
|
||||
self.kissport0 = self.kissdev[0]
|
||||
|
||||
LOG.debug("Creating AX25Interface")
|
||||
self.ax25int = interface.AX25Interface(kissport=self.kissport0, loop=self.loop)
|
||||
|
||||
LOG.debug("Creating APRSInterface")
|
||||
self.aprsint = APRSInterface(
|
||||
ax25int=self.ax25int,
|
||||
mycall=self.config["kiss"]["callsign"],
|
||||
log=LOG,
|
||||
)
|
||||
|
||||
def stop(self):
|
||||
LOG.debug(self.kissdev)
|
||||
self.kissdev._close()
|
||||
self.loop.stop()
|
||||
|
||||
def consumer(self, callback, callsign=None):
|
||||
if not callsign:
|
||||
callsign = self.config["ham"]["callsign"]
|
||||
self.aprsint.bind(callback=callback, callsign="WB4BOR", ssid=12, regex=False)
|
||||
|
||||
def send(self, msg):
|
||||
"""Send an APRS Message object."""
|
||||
payload = f"{msg._filter_for_send()}"
|
||||
self.aprsint.send_message(
|
||||
addressee=msg.tocall,
|
||||
message=payload,
|
||||
path=["WIDE1-1", "WIDE2-1"],
|
||||
oneshot=True,
|
||||
)
|
||||
|
||||
|
||||
def get_client():
|
||||
cl = KISSClient()
|
||||
return cl.client
|
@ -37,7 +37,8 @@ import click_completion
|
||||
# local imports here
|
||||
import aprsd
|
||||
from aprsd import (
|
||||
client, flask, messaging, packets, plugin, stats, threads, trace, utils,
|
||||
client, flask, kissclient, messaging, packets, plugin, stats, threads,
|
||||
trace, utils,
|
||||
)
|
||||
|
||||
|
||||
@ -458,16 +459,28 @@ def server(
|
||||
trace.setup_tracing(["method", "api"])
|
||||
stats.APRSDStats(config)
|
||||
|
||||
try:
|
||||
cl = client.Client(config)
|
||||
cl.client
|
||||
except LoginError:
|
||||
sys.exit(-1)
|
||||
|
||||
# Create the initial PM singleton and Register plugins
|
||||
plugin_manager = plugin.PluginManager(config)
|
||||
plugin_manager.setup_plugins()
|
||||
|
||||
if config["aprs"].get("enabled", True):
|
||||
try:
|
||||
cl = client.Client(config)
|
||||
cl.client
|
||||
except LoginError:
|
||||
sys.exit(-1)
|
||||
|
||||
rx_thread = threads.APRSDRXThread(
|
||||
msg_queues=threads.msg_queues,
|
||||
config=config,
|
||||
)
|
||||
rx_thread.start()
|
||||
else:
|
||||
LOG.info(
|
||||
"APRS network connection Not Enabled in config. This is"
|
||||
" for setups without internet connectivity.",
|
||||
)
|
||||
|
||||
# Now load the msgTrack from disk if any
|
||||
if flush:
|
||||
LOG.debug("Deleting saved MsgTrack.")
|
||||
@ -478,19 +491,15 @@ def server(
|
||||
messaging.MsgTrack().load()
|
||||
|
||||
packets.PacketList(config=config)
|
||||
packets.WatchList(config=config)
|
||||
|
||||
rx_thread = threads.APRSDRXThread(
|
||||
msg_queues=threads.msg_queues,
|
||||
config=config,
|
||||
)
|
||||
if kissclient.KISSClient.kiss_enabled(config):
|
||||
kcl = kissclient.KISSClient(config=config)
|
||||
# This initializes the client object.
|
||||
kcl.client
|
||||
|
||||
rx_thread.start()
|
||||
|
||||
if "watch_list" in config["aprsd"] and config["aprsd"]["watch_list"].get(
|
||||
"enabled",
|
||||
True,
|
||||
):
|
||||
packets.WatchList(config=config)
|
||||
kissrx_thread = threads.KISSRXThread(msg_queues=threads.msg_queues, config=config)
|
||||
kissrx_thread.start()
|
||||
|
||||
messaging.MsgTrack().restart()
|
||||
|
||||
|
@ -9,7 +9,7 @@ import re
|
||||
import threading
|
||||
import time
|
||||
|
||||
from aprsd import client, packets, stats, threads, trace, utils
|
||||
from aprsd import client, kissclient, packets, stats, threads, trace, utils
|
||||
|
||||
|
||||
LOG = logging.getLogger("APRSD")
|
||||
@ -18,6 +18,10 @@ LOG = logging.getLogger("APRSD")
|
||||
# and it's ok, but don't send a usage string back
|
||||
NULL_MESSAGE = -1
|
||||
|
||||
MESSAGE_TRANSPORT_TCPKISS = "tcpkiss"
|
||||
MESSAGE_TRANSPORT_SERIALKISS = "serialkiss"
|
||||
MESSAGE_TRANSPORT_APRSIS = "aprsis"
|
||||
|
||||
|
||||
class MsgTrack:
|
||||
"""Class to keep track of outstanding text messages.
|
||||
@ -228,7 +232,15 @@ class Message(metaclass=abc.ABCMeta):
|
||||
last_send_time = 0
|
||||
last_send_attempt = 0
|
||||
|
||||
def __init__(self, fromcall, tocall, msg_id=None):
|
||||
transport = None
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
fromcall,
|
||||
tocall,
|
||||
msg_id=None,
|
||||
transport=MESSAGE_TRANSPORT_APRSIS,
|
||||
):
|
||||
self.fromcall = fromcall
|
||||
self.tocall = tocall
|
||||
if not msg_id:
|
||||
@ -236,11 +248,18 @@ class Message(metaclass=abc.ABCMeta):
|
||||
c.increment()
|
||||
msg_id = c.value
|
||||
self.id = msg_id
|
||||
self.transport = transport
|
||||
|
||||
@abc.abstractmethod
|
||||
def send(self):
|
||||
"""Child class must declare."""
|
||||
|
||||
def get_transport(self):
|
||||
if self.transport == MESSAGE_TRANSPORT_APRSIS:
|
||||
return client.get_client()
|
||||
elif self.transport == MESSAGE_TRANSPORT_TCPKISS:
|
||||
return kissclient.get_client()
|
||||
|
||||
|
||||
class RawMessage(Message):
|
||||
"""Send a raw message.
|
||||
@ -252,8 +271,8 @@ class RawMessage(Message):
|
||||
|
||||
message = None
|
||||
|
||||
def __init__(self, message):
|
||||
super().__init__(None, None, msg_id=None)
|
||||
def __init__(self, message, transport=MESSAGE_TRANSPORT_APRSIS):
|
||||
super().__init__(None, None, msg_id=None, transport=transport)
|
||||
self.message = message
|
||||
|
||||
def dict(self):
|
||||
@ -282,7 +301,7 @@ class RawMessage(Message):
|
||||
|
||||
def send_direct(self):
|
||||
"""Send a message without a separate thread."""
|
||||
cl = client.get_client()
|
||||
cl = self.get_transport()
|
||||
log_message(
|
||||
"Sending Message Direct",
|
||||
str(self).rstrip("\n"),
|
||||
@ -290,7 +309,7 @@ class RawMessage(Message):
|
||||
tocall=self.tocall,
|
||||
fromcall=self.fromcall,
|
||||
)
|
||||
cl.sendall(str(self))
|
||||
cl.send(self)
|
||||
stats.APRSDStats().msgs_sent_inc()
|
||||
|
||||
|
||||
@ -299,8 +318,16 @@ class TextMessage(Message):
|
||||
|
||||
message = None
|
||||
|
||||
def __init__(self, fromcall, tocall, message, msg_id=None, allow_delay=True):
|
||||
super().__init__(fromcall, tocall, msg_id)
|
||||
def __init__(
|
||||
self,
|
||||
fromcall,
|
||||
tocall,
|
||||
message,
|
||||
msg_id=None,
|
||||
allow_delay=True,
|
||||
transport=MESSAGE_TRANSPORT_APRSIS,
|
||||
):
|
||||
super().__init__(fromcall, tocall, msg_id, transport=transport)
|
||||
self.message = message
|
||||
# do we try and save this message for later if we don't get
|
||||
# an ack? Some messages we don't want to do this ever.
|
||||
@ -354,7 +381,7 @@ class TextMessage(Message):
|
||||
|
||||
def send_direct(self):
|
||||
"""Send a message without a separate thread."""
|
||||
cl = client.get_client()
|
||||
cl = self.get_transport()
|
||||
log_message(
|
||||
"Sending Message Direct",
|
||||
str(self).rstrip("\n"),
|
||||
@ -362,7 +389,7 @@ class TextMessage(Message):
|
||||
tocall=self.tocall,
|
||||
fromcall=self.fromcall,
|
||||
)
|
||||
cl.sendall(str(self))
|
||||
cl.send(self)
|
||||
stats.APRSDStats().msgs_tx_inc()
|
||||
|
||||
|
||||
@ -382,7 +409,6 @@ class SendMessageThread(threads.APRSDThread):
|
||||
last send attempt is old enough.
|
||||
|
||||
"""
|
||||
cl = client.get_client()
|
||||
tracker = MsgTrack()
|
||||
# lets see if the message is still in the tracking queue
|
||||
msg = tracker.get(self.msg.id)
|
||||
@ -392,6 +418,7 @@ class SendMessageThread(threads.APRSDThread):
|
||||
LOG.info("Message Send Complete via Ack.")
|
||||
return False
|
||||
else:
|
||||
cl = msg.get_transport()
|
||||
send_now = False
|
||||
if msg.last_send_attempt == msg.retry_count:
|
||||
# we reached the send limit, don't send again
|
||||
@ -422,7 +449,7 @@ class SendMessageThread(threads.APRSDThread):
|
||||
retry_number=msg.last_send_attempt,
|
||||
msg_num=msg.id,
|
||||
)
|
||||
cl.sendall(str(msg))
|
||||
cl.send(msg)
|
||||
stats.APRSDStats().msgs_tx_inc()
|
||||
packets.PacketList().add(msg.dict())
|
||||
msg.last_send_time = datetime.datetime.now()
|
||||
@ -436,8 +463,8 @@ class SendMessageThread(threads.APRSDThread):
|
||||
class AckMessage(Message):
|
||||
"""Class for building Acks and sending them."""
|
||||
|
||||
def __init__(self, fromcall, tocall, msg_id):
|
||||
super().__init__(fromcall, tocall, msg_id=msg_id)
|
||||
def __init__(self, fromcall, tocall, msg_id, transport=MESSAGE_TRANSPORT_APRSIS):
|
||||
super().__init__(fromcall, tocall, msg_id=msg_id, transport=transport)
|
||||
|
||||
def dict(self):
|
||||
now = datetime.datetime.now()
|
||||
@ -463,6 +490,9 @@ class AckMessage(Message):
|
||||
self.id,
|
||||
)
|
||||
|
||||
def _filter_for_send(self):
|
||||
return f"ack{self.id}"
|
||||
|
||||
def send(self):
|
||||
LOG.debug(f"Send ACK({self.tocall}:{self.id}) to radio.")
|
||||
thread = SendAckThread(self)
|
||||
@ -470,7 +500,7 @@ class AckMessage(Message):
|
||||
|
||||
def send_direct(self):
|
||||
"""Send an ack message without a separate thread."""
|
||||
cl = client.get_client()
|
||||
cl = self.get_transport()
|
||||
log_message(
|
||||
"Sending ack",
|
||||
str(self).rstrip("\n"),
|
||||
@ -479,7 +509,7 @@ class AckMessage(Message):
|
||||
tocall=self.tocall,
|
||||
fromcall=self.fromcall,
|
||||
)
|
||||
cl.sendall(str(self))
|
||||
cl.send(self)
|
||||
|
||||
|
||||
class SendAckThread(threads.APRSDThread):
|
||||
@ -515,7 +545,7 @@ class SendAckThread(threads.APRSDThread):
|
||||
send_now = True
|
||||
|
||||
if send_now:
|
||||
cl = client.get_client()
|
||||
cl = self.ack.get_transport()
|
||||
log_message(
|
||||
"Sending ack",
|
||||
str(self.ack).rstrip("\n"),
|
||||
@ -524,7 +554,7 @@ class SendAckThread(threads.APRSDThread):
|
||||
tocall=self.ack.tocall,
|
||||
retry_number=self.ack.last_send_attempt,
|
||||
)
|
||||
cl.sendall(str(self.ack))
|
||||
cl.send(self.ack)
|
||||
stats.APRSDStats().ack_tx_inc()
|
||||
packets.PacketList().add(self.ack.dict())
|
||||
self.ack.last_send_attempt += 1
|
||||
|
@ -8,7 +8,7 @@ import tracemalloc
|
||||
|
||||
import aprslib
|
||||
|
||||
from aprsd import client, messaging, packets, plugin, stats, utils
|
||||
from aprsd import client, kissclient, messaging, packets, plugin, stats, utils
|
||||
|
||||
|
||||
LOG = logging.getLogger("APRSD")
|
||||
@ -180,9 +180,10 @@ class APRSDRXThread(APRSDThread):
|
||||
|
||||
class APRSDProcessPacketThread(APRSDThread):
|
||||
|
||||
def __init__(self, packet, config):
|
||||
def __init__(self, packet, config, transport="aprsis"):
|
||||
self.packet = packet
|
||||
self.config = config
|
||||
self.transport = transport
|
||||
name = self.packet["raw"][:10]
|
||||
super().__init__(f"RX_PACKET-{name}")
|
||||
|
||||
@ -237,6 +238,7 @@ class APRSDProcessPacketThread(APRSDThread):
|
||||
self.config["aprs"]["login"],
|
||||
fromcall,
|
||||
msg_id=msg_id,
|
||||
transport=self.transport,
|
||||
)
|
||||
ack.send()
|
||||
|
||||
@ -255,6 +257,7 @@ class APRSDProcessPacketThread(APRSDThread):
|
||||
self.config["aprs"]["login"],
|
||||
fromcall,
|
||||
subreply,
|
||||
transport=self.transport,
|
||||
)
|
||||
msg.send()
|
||||
|
||||
@ -271,6 +274,7 @@ class APRSDProcessPacketThread(APRSDThread):
|
||||
self.config["aprs"]["login"],
|
||||
fromcall,
|
||||
reply,
|
||||
transport=self.transport,
|
||||
)
|
||||
msg.send()
|
||||
|
||||
@ -283,6 +287,7 @@ class APRSDProcessPacketThread(APRSDThread):
|
||||
self.config["aprs"]["login"],
|
||||
fromcall,
|
||||
reply,
|
||||
transport=self.transport,
|
||||
)
|
||||
msg.send()
|
||||
except Exception as ex:
|
||||
@ -294,6 +299,7 @@ class APRSDProcessPacketThread(APRSDThread):
|
||||
self.config["aprs"]["login"],
|
||||
fromcall,
|
||||
reply,
|
||||
transport=self.transport,
|
||||
)
|
||||
msg.send()
|
||||
|
||||
@ -314,3 +320,66 @@ class APRSDTXThread(APRSDThread):
|
||||
pass
|
||||
# Continue to loop
|
||||
return True
|
||||
|
||||
|
||||
class KISSRXThread(APRSDThread):
|
||||
"""Thread that connects to direwolf's TCPKISS interface.
|
||||
|
||||
All Packets are processed and sent back out the direwolf
|
||||
interface instead of the aprs-is server.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, msg_queues, config):
|
||||
super().__init__("KISSRX_MSG")
|
||||
self.msg_queues = msg_queues
|
||||
self.config = config
|
||||
|
||||
def stop(self):
|
||||
self.thread_stop = True
|
||||
kissclient.get_client().stop()
|
||||
|
||||
def loop(self):
|
||||
kiss_client = kissclient.get_client()
|
||||
|
||||
# setup the consumer of messages and block until a messages
|
||||
try:
|
||||
# This will register a packet consumer with aprslib
|
||||
# When new packets come in the consumer will process
|
||||
# the packet
|
||||
|
||||
# Do a partial here because the consumer signature doesn't allow
|
||||
# For kwargs to be passed in to the consumer func we declare
|
||||
# and the aprslib developer didn't want to allow a PR to add
|
||||
# kwargs. :(
|
||||
# https://github.com/rossengeorgiev/aprs-python/pull/56
|
||||
kiss_client.consumer(self.process_packet, callsign=self.config["kiss"]["callsign"])
|
||||
kiss_client.loop.run_forever()
|
||||
|
||||
except aprslib.exceptions.ConnectionDrop:
|
||||
LOG.error("Connection dropped, reconnecting")
|
||||
time.sleep(5)
|
||||
# Force the deletion of the client object connected to aprs
|
||||
# This will cause a reconnect, next time client.get_client()
|
||||
# is called
|
||||
client.Client().reset()
|
||||
# Continue to loop
|
||||
|
||||
def process_packet(self, interface, frame):
|
||||
"""Process a packet recieved from aprs-is server."""
|
||||
|
||||
LOG.debug(f"Got an APRS Frame '{frame}'")
|
||||
# try and nuke the * from the fromcall sign.
|
||||
frame.header._source._ch = False
|
||||
payload = str(frame.payload.decode())
|
||||
msg = f"{str(frame.header)}:{payload}"
|
||||
LOG.debug(f"Decoding {msg}")
|
||||
|
||||
packet = aprslib.parse(msg)
|
||||
LOG.debug(packet)
|
||||
thread = APRSDProcessPacketThread(
|
||||
packet=packet, config=self.config,
|
||||
transport=messaging.MESSAGE_TRANSPORT_TCPKISS,
|
||||
)
|
||||
thread.start()
|
||||
return
|
||||
|
@ -37,11 +37,24 @@ DEFAULT_DATE_FORMAT = "%m/%d/%Y %I:%M:%S %p"
|
||||
DEFAULT_CONFIG_DICT = {
|
||||
"ham": {"callsign": "NOCALL"},
|
||||
"aprs": {
|
||||
"login": "NOCALL",
|
||||
"enabled": True,
|
||||
"login": "CALLSIGN",
|
||||
"password": "00000",
|
||||
"host": "rotate.aprs2.net",
|
||||
"port": 14580,
|
||||
},
|
||||
"kiss": {
|
||||
"tcp": {
|
||||
"enabled": False,
|
||||
"host": "direwolf.ip.address",
|
||||
"port": "8001",
|
||||
},
|
||||
"serial": {
|
||||
"enabled": False,
|
||||
"device": "/dev/ttyS0",
|
||||
"baudrate": 9600,
|
||||
},
|
||||
},
|
||||
"aprsd": {
|
||||
"logfile": "/tmp/aprsd.log",
|
||||
"logformat": DEFAULT_LOG_FORMAT,
|
||||
@ -172,6 +185,9 @@ def add_config_comments(raw_yaml):
|
||||
# lets insert a comment
|
||||
raw_yaml = insert_str(
|
||||
raw_yaml,
|
||||
"\n # Set enabled to False if there is no internet connectivity."
|
||||
"\n # This is useful for a direwolf KISS aprs connection only. "
|
||||
"\n"
|
||||
"\n # Get the passcode for your callsign here: "
|
||||
"\n # https://apps.magicbug.co.uk/passcode",
|
||||
end_idx,
|
||||
|
@ -220,7 +220,7 @@ function updateQuadData(chart, label, first, second, third, fourth) {
|
||||
|
||||
function update_stats( data ) {
|
||||
$("#version").text( data["stats"]["aprsd"]["version"] );
|
||||
$("#aprsis").html( "APRS-IS Server: <a href='http://status.aprs2.net' >" + data["stats"]["aprs-is"]["server"] + "</a>" );
|
||||
$("#aprs_connection").html( data["aprs_connection"] );
|
||||
$("#uptime").text( "uptime: " + data["stats"]["aprsd"]["uptime"] );
|
||||
const html_pretty = Prism.highlight(JSON.stringify(data, null, '\t'), Prism.languages.json, 'json');
|
||||
$("#jsonstats").html(html_pretty);
|
||||
|
@ -58,7 +58,7 @@
|
||||
<div class='left floated ten wide column'>
|
||||
<span style='color: green'>{{ callsign }}</span>
|
||||
connected to
|
||||
<span style='color: blue' id='aprsis'>NONE</span>
|
||||
<span style='color: blue' id='aprs_connection'>{{ aprs_connection|safe }}</span>
|
||||
</div>
|
||||
|
||||
<div class='right floated four wide column'>
|
||||
|
@ -1,3 +1,4 @@
|
||||
aioax25>=0.0.10
|
||||
aprslib
|
||||
click
|
||||
click-completion
|
||||
|
@ -4,6 +4,8 @@
|
||||
#
|
||||
# pip-compile requirements.in
|
||||
#
|
||||
aioax25==0.0.10
|
||||
# via -r requirements.in
|
||||
aprslib==0.6.47
|
||||
# via -r requirements.in
|
||||
backoff==1.10.0
|
||||
@ -21,6 +23,8 @@ click==7.1.2
|
||||
# -r requirements.in
|
||||
# click-completion
|
||||
# flask
|
||||
contexter==0.1.4
|
||||
# via signalslot
|
||||
cryptography==3.4.7
|
||||
# via pyopenssl
|
||||
dnspython==2.1.0
|
||||
@ -72,6 +76,8 @@ pycparser==2.20
|
||||
# via cffi
|
||||
pyopenssl==20.0.1
|
||||
# via opencage
|
||||
pyserial==3.5
|
||||
# via aioax25
|
||||
python-dateutil==2.8.1
|
||||
# via pandas
|
||||
pytz==2021.1
|
||||
@ -88,6 +94,8 @@ requests==2.25.1
|
||||
# yfinance
|
||||
shellingham==1.4.0
|
||||
# via click-completion
|
||||
signalslot==0.1.2
|
||||
# via aioax25
|
||||
six==1.15.0
|
||||
# via
|
||||
# -r requirements.in
|
||||
@ -96,12 +104,15 @@ six==1.15.0
|
||||
# opencage
|
||||
# pyopenssl
|
||||
# python-dateutil
|
||||
# signalslot
|
||||
thesmuggler==1.0.1
|
||||
# via -r requirements.in
|
||||
update-checker==0.18.0
|
||||
# via -r requirements.in
|
||||
urllib3==1.26.5
|
||||
# via requests
|
||||
weakrefmethod==1.0.3
|
||||
# via signalslot
|
||||
werkzeug==1.0.1
|
||||
# via flask
|
||||
yfinance==0.1.59
|
||||
|
Loading…
Reference in New Issue
Block a user