aprsd/aprsd/cmds/send_message.py

164 lines
4.4 KiB
Python

import logging
import sys
import time
import aprslib
from aprslib.exceptions import LoginError
import click
import aprsd
from aprsd import cli_helper, client, packets
from aprsd.aprsd import cli
LOG = logging.getLogger("APRSD")
@cli.command()
@cli_helper.add_options(cli_helper.common_options)
@click.option(
"--aprs-login",
envvar="APRS_LOGIN",
show_envvar=True,
help="What callsign to send the message from. Defaults to config entry.",
)
@click.option(
"--aprs-password",
envvar="APRS_PASSWORD",
show_envvar=True,
help="the APRS-IS password for APRS_LOGIN. Defaults to config entry.",
)
@click.option(
"--no-ack",
"-n",
is_flag=True,
show_default=True,
default=False,
help="Don't wait for an ack, just sent it to APRS-IS and bail.",
)
@click.option(
"--wait-response",
"-w",
is_flag=True,
show_default=True,
default=False,
help="Wait for a response to the message?",
)
@click.option("--raw", default=None, help="Send a raw message. Implies --no-ack")
@click.argument("tocallsign", required=True)
@click.argument("command", nargs=-1, required=True)
@click.pass_context
@cli_helper.process_standard_options
def send_message(
ctx,
aprs_login,
aprs_password,
no_ack,
wait_response,
raw,
tocallsign,
command,
):
"""Send a message to a callsign via APRS_IS."""
global got_ack, got_response
config = ctx.obj["config"]
quiet = ctx.obj["quiet"]
if not aprs_login:
if not config.exists("aprs.login"):
click.echo("Must set --aprs_login or APRS_LOGIN")
ctx.exit(-1)
return
else:
config["aprs"]["login"] = aprs_login
if not aprs_password:
if not config.exists("aprs.password"):
click.echo("Must set --aprs-password or APRS_PASSWORD")
ctx.exit(-1)
return
else:
config["aprs"]["password"] = aprs_password
LOG.info(f"APRSD LISTEN Started version: {aprsd.__version__}")
if type(command) is tuple:
command = " ".join(command)
if not quiet:
if raw:
LOG.info(f"L'{aprs_login}' R'{raw}'")
else:
LOG.info(f"L'{aprs_login}' To'{tocallsign}' C'{command}'")
packets.PacketList(config=config)
packets.WatchList(config=config)
packets.SeenList(config=config)
got_ack = False
got_response = False
def rx_packet(packet):
global got_ack, got_response
cl = client.factory.create()
packet = cl.decode_packet(packet)
packet.log("RX_PKT")
# LOG.debug("Got packet back {}".format(packet))
if isinstance(packet, packets.AckPacket):
got_ack = True
else:
got_response = True
from_call = packet.from_call
our_call = config["aprsd"]["callsign"].lower()
ack_pkt = packets.AckPacket(
from_call=our_call,
to_call=from_call,
msgNo=packet.msgNo,
)
ack_pkt.send_direct()
if got_ack:
if wait_response:
if got_response:
sys.exit(0)
else:
sys.exit(0)
try:
client.ClientFactory.setup(config)
client.factory.create().client
except LoginError:
sys.exit(-1)
# Send a message
# then we setup a consumer to rx messages
# We should get an ack back as well as a new message
# we should bail after we get the ack and send an ack back for the
# message
if raw:
pkt = packets.Packet(from_call="", to_call="", raw=raw)
pkt.send_direct()
sys.exit(0)
else:
pkt = packets.MessagePacket(
from_call=aprs_login,
to_call=tocallsign,
message_text=command,
)
pkt.send_direct()
if no_ack:
sys.exit(0)
try:
# This will register a packet consumer with aprslib
# When new packets come in the consumer will process
# the packet
aprs_client = client.factory.create().client
aprs_client.consumer(rx_packet, raw=False)
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
aprs_client.reset()