From 319de5cf42807f5bb2487bd7670d56cdb7df77d3 Mon Sep 17 00:00:00 2001 From: Logan Cusano Date: Fri, 1 Apr 2022 00:46:34 -0400 Subject: [PATCH 01/32] Initial changes to handle GQRX process --- BotResources.py | 8 ++++ bot.py | 12 ++++- gqrxHandler.py | 121 +++++++++++++++++++++++++++++++++++++++++++++--- op25Handler.py | 2 +- 4 files changed, 134 insertions(+), 9 deletions(-) diff --git a/BotResources.py b/BotResources.py index b8b8c43..a87ea78 100644 --- a/BotResources.py +++ b/BotResources.py @@ -5,18 +5,26 @@ from datetime import date from os.path import exists from NoiseGatev2 import AudioStream +# Handler configs PDB_ACCEPTABLE_HANDLERS = {'gqrx': { 'Modes': ['wfm', 'fm'] }, 'op25': { 'Modes': ['d', 'p25'] }} + +# Known bot IDs PDB_KNOWN_BOT_IDS = {756327271597473863: "Greada", 915064996994633729: "Jorn", 943742040255115304: "Brent"} +# Default value to set noisegate on new or unknown profiles DEFAULT_NOISEGATE_THRESHOLD = 50 +# Initialize the logger for this file LOGGER = logging.getLogger('Discord_Radio_Bot.Bot_Resources') +# Location of the gqrx binary +GQRX_BIN_LOCATION = "/usr/bin/" +GQRX_BIN = "/usr/bin/gqrx" def check_if_config_exists(): if exists('./config.ini'): diff --git a/bot.py b/bot.py index c33f2b6..143a53a 100644 --- a/bot.py +++ b/bot.py @@ -338,6 +338,7 @@ class Bot(commands.Bot): self.logger.info("Starting GQRX handler") from gqrxHandler import GQRXHandler self.GQRXHandler = GQRXHandler() + self.GQRXHandler.start() self.possible_modes = BotResources.PDB_ACCEPTABLE_HANDLERS['gqrx']['Modes'] elif self.Handler == 'op25': @@ -435,7 +436,9 @@ class Bot(commands.Bot): if self.Handler == 'gqrx': # Set the settings in GQRX - self.GQRXHandler.set_all_settings(self.mode, self.squelch, self.freq) + self.GQRXHandler.set_gqrx_parameters(_frequency=self.freq, _squelch=self.squelch, + _fm_mode=self.mode, _output_device_name=self.DEVICE_NAME, + _start=True) elif self.Handler == 'op25': self.OP25Handler.set_op25_parameters(self.freq, _start=True, _output_device_name=self.DEVICE_NAME) @@ -447,11 +450,16 @@ class Bot(commands.Bot): def stop_sdr(self): if self.sdr_started: # Wait for the running processes to close + + # Close the GQRX handler + if self.Handler == 'gqrx': + self.GQRXHandler.set_gqrx_parameters(_stop=True) + # Close the OP25 handler if self.Handler == 'op25': self.OP25Handler.set_op25_parameters(_stop=True) # self.OP25Handler.join() - # Need a way to 'close' GQRX + self.sdr_started = False # Set the activity of the bot diff --git a/gqrxHandler.py b/gqrxHandler.py index 2727a13..58a1f4b 100644 --- a/gqrxHandler.py +++ b/gqrxHandler.py @@ -1,18 +1,114 @@ +import shutil import logging +import threading +import subprocess from telnetlib import Telnet -from BotResources import check_negative +from BotResources import * from time import sleep -class GQRXHandler(): - def __init__(self, hostname: str = "localhost", port: int = 7356): - self.logger = logging.getLogger("Discord_Radio_Bot.GQRXHandler") - self.hostname = hostname - self.port = port +class GQRXHandler(threading.Thread): + def __init__(self): + super().__init__() + self.GQRXDir: str = GQRX_BIN_LOCATION + self.GQRXEXE: str = shutil.which(GQRX_BIN) + self.GQRXProc = None + + self.Frequency = None + + self.Mode = None + self.Frequency = None + self.Squelch = None + + self.Start_GQRX = False + self.Stop_GQRX = False + + self.Output_Device_Name = None + + self.hostname = "localhost" + self.port = 7356 self.tel_conn = None + self.open_gqrx() + self.create_telnet_connection() + self.logger = logging.getLogger("Discord_Radio_Bot.GQRXHandler") + + def run(self) -> None: + while True: + if self.Start_GQRX: + self.open_gqrx() + + self.Start_GQRX = False + self.Stop_GQRX = False + + while not self.Stop_GQRX: + sleep(1) + + self.close_gqrx() + + sleep(.5) + + def set_gqrx_parameters(self, _frequency: str = False, _start: bool = False, _stop: bool = False, + _output_device_name: str = None, _fm_mode: str = None, _squelch: int = None, + _hostname: str = None, _port: int = None): + if _frequency: + self.Frequency = _frequency + + if _output_device_name: + self.Output_Device_Name = _output_device_name + + if _fm_mode: + self.Mode = _fm_mode + + if _squelch: + self.Squelch = _squelch + + if _hostname: + self.hostname = _hostname + self.Start_GQRX = True + + if _port: + self.port = _port + self.Start_GQRX = True + + if _start: + self.Start_GQRX = _start + + if _stop: + self.Stop_GQRX = _stop + + def open_gqrx(self): + if self.GQRXProc is not None: + self.close_gqrx() + + gqrx_kwargs = [f""] + + self.logger.info(f"Starting GQRX") + + self.logger.debug(f"GQRX Keyword Args: {gqrx_kwargs}") + + self.GQRXProc = subprocess.Popen(gqrx_kwargs, executable=self.GQRXEXE, shell=False, cwd=self.GQRXDir) + + def close_gqrx(self): + self.logger.info(f"Closing GQRX") + try: + self.GQRXProc.kill() + + seconds_waited = 0 + while self.GQRXProc.poll() is None: + # Terminate the process every 5 seconds + if seconds_waited % 5 == 0: + self.logger.info("Terminating GQRX") + self.GQRXProc.terminate() + sleep(1) + self.logger.debug(f"Waited {seconds_waited} seconds") + seconds_waited += 1 + + except Exception as e: + self.logger.error(e) + def create_telnet_connection(self): self.logger.info("Creating connection") self.tel_conn = Telnet(self.hostname, self.port) @@ -23,6 +119,19 @@ class GQRXHandler(): self.tel_conn.write(bytes(f"F {int(freq)}", 'utf-8')) self.tel_conn.read_until(b'RPRT 0') + def check_dsp(self): + self.logger.debug(f"Checking if DSP is running on GQRX") + self.tel_conn.write(bytes(f"u DSP", 'utf-8')) + if self.tel_conn.read_some() == b"1": + return True + else: + return False + + def start_dsp(self): + self.logger.debug(f"Starting DSP on GQRX") + self.tel_conn.write(bytes(f"U DSP 1", 'utf-8')) + self.tel_conn.read_until(b'RPRT 0') + def change_squelch(self, squelch): if not check_negative(squelch): squelch = float(-abs(squelch)) diff --git a/op25Handler.py b/op25Handler.py index 947f62a..1c828cf 100644 --- a/op25Handler.py +++ b/op25Handler.py @@ -81,7 +81,7 @@ class OP25Handler(threading.Thread): while self.OP25Proc.poll() is None: # Terminate the process every 5 seconds if seconds_waited % 5 == 0: - self.logger.debug("Terminating OP25") + self.logger.info("Terminating OP25") self.OP25Proc.terminate() time.sleep(1) self.logger.debug(f"Waited {seconds_waited} seconds") From e26ae52399370067de80d7094f45113798cc12b8 Mon Sep 17 00:00:00 2001 From: Logan Cusano Date: Fri, 1 Apr 2022 00:50:28 -0400 Subject: [PATCH 02/32] Wrong location of the logger --- gqrxHandler.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gqrxHandler.py b/gqrxHandler.py index 58a1f4b..411277d 100644 --- a/gqrxHandler.py +++ b/gqrxHandler.py @@ -13,6 +13,8 @@ class GQRXHandler(threading.Thread): self.GQRXEXE: str = shutil.which(GQRX_BIN) self.GQRXProc = None + self.logger = logging.getLogger("Discord_Radio_Bot.GQRXHandler") + self.Frequency = None self.Mode = None @@ -33,8 +35,6 @@ class GQRXHandler(threading.Thread): self.create_telnet_connection() - self.logger = logging.getLogger("Discord_Radio_Bot.GQRXHandler") - def run(self) -> None: while True: if self.Start_GQRX: From 21aacde1306afcaf85869fc389646cc45efb1f55 Mon Sep 17 00:00:00 2001 From: Logan Cusano Date: Fri, 1 Apr 2022 00:51:34 -0400 Subject: [PATCH 03/32] Moved the main inits to when the bot is run --- gqrxHandler.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/gqrxHandler.py b/gqrxHandler.py index 411277d..3c15baa 100644 --- a/gqrxHandler.py +++ b/gqrxHandler.py @@ -31,11 +31,10 @@ class GQRXHandler(threading.Thread): self.tel_conn = None + def run(self) -> None: self.open_gqrx() self.create_telnet_connection() - - def run(self) -> None: while True: if self.Start_GQRX: self.open_gqrx() From b972d09a65b21d277f23f96f8b7aa9fe3a69d8a7 Mon Sep 17 00:00:00 2001 From: Logan Cusano Date: Fri, 1 Apr 2022 01:00:32 -0400 Subject: [PATCH 04/32] Handling the delay in GQRX opening and being 'usable' Handling the delay in GQRX opening and being 'usable' --- gqrxHandler.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/gqrxHandler.py b/gqrxHandler.py index 3c15baa..bead1ac 100644 --- a/gqrxHandler.py +++ b/gqrxHandler.py @@ -2,6 +2,7 @@ import shutil import logging import threading import subprocess +import time from telnetlib import Telnet from BotResources import * from time import sleep @@ -90,6 +91,9 @@ class GQRXHandler(threading.Thread): self.GQRXProc = subprocess.Popen(gqrx_kwargs, executable=self.GQRXEXE, shell=False, cwd=self.GQRXDir) + while not self.tel_conn(): + sleep(.5) + def close_gqrx(self): self.logger.info(f"Closing GQRX") try: @@ -111,7 +115,12 @@ class GQRXHandler(threading.Thread): def create_telnet_connection(self): self.logger.info("Creating connection") self.tel_conn = Telnet(self.hostname, self.port) - self.tel_conn.open(self.hostname, self.port) + try: + self.tel_conn.open(self.hostname, self.port) + return True + except ConnectionRefusedError as err: + self.logger.warning(err) + return False def change_freq(self, freq): self.logger.debug(f"Changing freq to {freq}") From fd62da0c6f5aeb6cad0cb136dc7020f51b73fd00 Mon Sep 17 00:00:00 2001 From: Logan Cusano Date: Fri, 1 Apr 2022 01:05:57 -0400 Subject: [PATCH 05/32] Silly bug --- gqrxHandler.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gqrxHandler.py b/gqrxHandler.py index bead1ac..2c85636 100644 --- a/gqrxHandler.py +++ b/gqrxHandler.py @@ -91,7 +91,7 @@ class GQRXHandler(threading.Thread): self.GQRXProc = subprocess.Popen(gqrx_kwargs, executable=self.GQRXEXE, shell=False, cwd=self.GQRXDir) - while not self.tel_conn(): + while not self.tel_conn: sleep(.5) def close_gqrx(self): From 5d1a58ee876093500c1793f423a06ba381058d0e Mon Sep 17 00:00:00 2001 From: Logan Cusano Date: Fri, 1 Apr 2022 01:07:23 -0400 Subject: [PATCH 06/32] Var got set before the error check --- gqrxHandler.py | 1 + 1 file changed, 1 insertion(+) diff --git a/gqrxHandler.py b/gqrxHandler.py index 2c85636..07b25e6 100644 --- a/gqrxHandler.py +++ b/gqrxHandler.py @@ -120,6 +120,7 @@ class GQRXHandler(threading.Thread): return True except ConnectionRefusedError as err: self.logger.warning(err) + self.tel_conn = None return False def change_freq(self, freq): From 8debd690f1794933ab2fef8f4461b7af43e1109e Mon Sep 17 00:00:00 2001 From: Logan Cusano Date: Fri, 1 Apr 2022 01:08:54 -0400 Subject: [PATCH 07/32] Better logging --- gqrxHandler.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gqrxHandler.py b/gqrxHandler.py index 07b25e6..91d38ff 100644 --- a/gqrxHandler.py +++ b/gqrxHandler.py @@ -93,6 +93,7 @@ class GQRXHandler(threading.Thread): while not self.tel_conn: sleep(.5) + self.logger.debug(f"Waiting for GQRX to start") def close_gqrx(self): self.logger.info(f"Closing GQRX") @@ -117,6 +118,7 @@ class GQRXHandler(threading.Thread): self.tel_conn = Telnet(self.hostname, self.port) try: self.tel_conn.open(self.hostname, self.port) + self.logger.debug(f"GQRX is open") return True except ConnectionRefusedError as err: self.logger.warning(err) From 676936eb6fea94d1a38dd950cf9cc5a1e04fde39 Mon Sep 17 00:00:00 2001 From: Logan Cusano Date: Fri, 1 Apr 2022 01:10:12 -0400 Subject: [PATCH 08/32] More intelligent init of the handler --- gqrxHandler.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gqrxHandler.py b/gqrxHandler.py index 91d38ff..89a8e4a 100644 --- a/gqrxHandler.py +++ b/gqrxHandler.py @@ -32,9 +32,9 @@ class GQRXHandler(threading.Thread): self.tel_conn = None - def run(self) -> None: self.open_gqrx() + def run(self) -> None: self.create_telnet_connection() while True: if self.Start_GQRX: From bbca25ce3f910728ea2e2cf43133e1ff9502175e Mon Sep 17 00:00:00 2001 From: Logan Cusano Date: Fri, 1 Apr 2022 01:55:14 -0400 Subject: [PATCH 09/32] Getting closer on the GQRX Handler. Doesn't close properly --- gqrxHandler.py | 52 +++++++++++++++++++++++++++++++++----------------- 1 file changed, 34 insertions(+), 18 deletions(-) diff --git a/gqrxHandler.py b/gqrxHandler.py index 91d38ff..f8c2685 100644 --- a/gqrxHandler.py +++ b/gqrxHandler.py @@ -33,9 +33,6 @@ class GQRXHandler(threading.Thread): self.tel_conn = None def run(self) -> None: - self.open_gqrx() - - self.create_telnet_connection() while True: if self.Start_GQRX: self.open_gqrx() @@ -43,27 +40,36 @@ class GQRXHandler(threading.Thread): self.Start_GQRX = False self.Stop_GQRX = False + self.logger.debug("GQRX is open, waiting for it to close") + while not self.Stop_GQRX: sleep(1) - self.close_gqrx() + self.logger.debug('Request to close GQRX') + self.close_gqrx() sleep(.5) def set_gqrx_parameters(self, _frequency: str = False, _start: bool = False, _stop: bool = False, _output_device_name: str = None, _fm_mode: str = None, _squelch: int = None, - _hostname: str = None, _port: int = None): + _hostname: str = None, _port: int = None, _start_dsp: bool = None): if _frequency: self.Frequency = _frequency + if self.GQRXProc: + self.change_freq(_frequency) if _output_device_name: self.Output_Device_Name = _output_device_name if _fm_mode: self.Mode = _fm_mode + if self.GQRXProc: + self.change_mode(_fm_mode) if _squelch: self.Squelch = _squelch + if self.GQRXProc: + self.change_squelch(_squelch) if _hostname: self.hostname = _hostname @@ -73,6 +79,9 @@ class GQRXHandler(threading.Thread): self.port = _port self.Start_GQRX = True + if _start_dsp: + self.start_dsp() + if _start: self.Start_GQRX = _start @@ -92,9 +101,15 @@ class GQRXHandler(threading.Thread): self.GQRXProc = subprocess.Popen(gqrx_kwargs, executable=self.GQRXEXE, shell=False, cwd=self.GQRXDir) while not self.tel_conn: + self.create_telnet_connection() sleep(.5) self.logger.debug(f"Waiting for GQRX to start") + self.start_dsp() + + self.set_all_settings(_squelch=self.Squelch, _mode=self.Mode, _freq=self.Frequency) + self.logger.debug('Finished opening GQRX') + def close_gqrx(self): self.logger.info(f"Closing GQRX") try: @@ -115,21 +130,16 @@ class GQRXHandler(threading.Thread): def create_telnet_connection(self): self.logger.info("Creating connection") - self.tel_conn = Telnet(self.hostname, self.port) try: + self.tel_conn = Telnet(self.hostname, self.port) self.tel_conn.open(self.hostname, self.port) self.logger.debug(f"GQRX is open") return True - except ConnectionRefusedError as err: + except Exception as err: self.logger.warning(err) self.tel_conn = None return False - def change_freq(self, freq): - self.logger.debug(f"Changing freq to {freq}") - self.tel_conn.write(bytes(f"F {int(freq)}", 'utf-8')) - self.tel_conn.read_until(b'RPRT 0') - def check_dsp(self): self.logger.debug(f"Checking if DSP is running on GQRX") self.tel_conn.write(bytes(f"u DSP", 'utf-8')) @@ -139,8 +149,14 @@ class GQRXHandler(threading.Thread): return False def start_dsp(self): - self.logger.debug(f"Starting DSP on GQRX") - self.tel_conn.write(bytes(f"U DSP 1", 'utf-8')) + if not self.check_dsp(): + self.logger.debug(f"Starting DSP on GQRX") + self.tel_conn.write(bytes(f"U DSP 1", 'utf-8')) + self.tel_conn.read_until(b'RPRT 0') + + def change_freq(self, freq): + self.logger.debug(f"Changing freq to {freq}") + self.tel_conn.write(bytes(f"F {int(freq)}", 'utf-8')) self.tel_conn.read_until(b'RPRT 0') def change_squelch(self, squelch): @@ -155,8 +171,8 @@ class GQRXHandler(threading.Thread): self.tel_conn.write(bytes(f"M {str(mode)}", 'utf-8')) self.tel_conn.read_until(b'RPRT 0') - def set_all_settings(self, mode, squelch, freq): + def set_all_settings(self, _mode, _squelch, _freq): self.change_squelch(0) - self.change_mode(mode) - self.change_freq(freq) - self.change_squelch(squelch) + self.change_mode(_mode) + self.change_freq(_freq) + self.change_squelch(_squelch) From 5a3729627b5902c7244ab5b868e3e387fff9df99 Mon Sep 17 00:00:00 2001 From: Logan Cusano Date: Sat, 9 Apr 2022 01:13:06 -0400 Subject: [PATCH 10/32] GQRX Changes - Checks for GQRX config file - If one exists, reset the 'crashed' option - If one does not, create one from the template - New templates package - Useful for storing large files to be called on later --- gqrxHandler.py | 37 ++++++++++++++++++++++++++- templates/__init__.py | 0 templates/gqrx_config_template.py | 42 +++++++++++++++++++++++++++++++ 3 files changed, 78 insertions(+), 1 deletion(-) create mode 100644 templates/__init__.py create mode 100644 templates/gqrx_config_template.py diff --git a/gqrxHandler.py b/gqrxHandler.py index f8c2685..a2f1a52 100644 --- a/gqrxHandler.py +++ b/gqrxHandler.py @@ -3,13 +3,30 @@ import logging import threading import subprocess import time +from pathlib import Path from telnetlib import Telnet from BotResources import * from time import sleep + +def reset_crashed(_config_path): + config = configparser.SafeConfigParser() + config.read(_config_path) + if config.has_section('General'): + if config.getboolean('General', 'crashed'): + config['General']['crashed'] = 'false' + with open(_config_path, 'w') as config_file: + config.write(config_file) + return True + + else: + return False + + class GQRXHandler(threading.Thread): def __init__(self): super().__init__() + self.GQRX_Config_Path = Path(f"{Path.home()}/.config/gqrx/drb_defaults.conf") self.GQRXDir: str = GQRX_BIN_LOCATION self.GQRXEXE: str = shutil.which(GQRX_BIN) self.GQRXProc = None @@ -92,7 +109,11 @@ class GQRXHandler(threading.Thread): if self.GQRXProc is not None: self.close_gqrx() - gqrx_kwargs = [f""] + gqrx_kwargs = [f"-c drb_defaults.conf"] + + self.logger.info(f"Resetting 'crashed' option in the GQRX config") + + self.reset_or_create_config() self.logger.info(f"Starting GQRX") @@ -176,3 +197,17 @@ class GQRXHandler(threading.Thread): self.change_mode(_mode) self.change_freq(_freq) self.change_squelch(_squelch) + + def reset_or_create_config(self): + if self.GQRX_Config_Path.is_file(): + self.logger.debug(f"GQRX Config exists, resetting 'crashed' setting") + reset_crashed(_config_path=self.GQRX_Config_Path) + else: + self.logger.debug(f"GQRX config does not exist, creating it from template") + from templates.gqrx_config_template import drb_defaults + config = drb_defaults + try: + with open(self.GQRX_Config_Path, 'w+') as config_file: + config_file.write(config) + except OSError as err: + self.logger.error(err) diff --git a/templates/__init__.py b/templates/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/templates/gqrx_config_template.py b/templates/gqrx_config_template.py new file mode 100644 index 0000000..501e31a --- /dev/null +++ b/templates/gqrx_config_template.py @@ -0,0 +1,42 @@ +drb_defaults = """[General] +configversion=2 +crashed=false + +[audio] +gain=-20 +udp_host=localhost + +[dxcluster] +DXCAddress=localhost +DXCFilter= +DXCPort=7300 +DXCSpotTimeout=10 +DXCUsername=nocall + +[fft] +averaging=85 +fft_window=5 +waterfall_span=1 + +[gui] +geometry=@ByteArray(\x1\xd9\xd0\xcb\0\x3\0\0\0\0\x4t\0\0\0$\0\0\a\x7f\0\0\x3\x12\0\0\x4v\0\0\0\x42\0\0\a\x7f\0\0\x3\x12\0\0\0\0\0\0\0\0\a\x80\0\0\x4v\0\0\0\x42\0\0\a\x7f\0\0\x3\x12) +state=@ByteArray(\0\0\0\xff\0\0\0\0\xfd\0\0\0\x2\0\0\0\x1\0\0\x1G\0\0\x2t\xfc\x2\0\0\0\x2\xfc\0\0\0\x42\0\0\x1\x89\0\0\x1\x89\0\b\0!\xfa\0\0\0\x1\x2\0\0\0\x3\xfb\0\0\0\x18\0\x44\0o\0\x63\0k\0I\0n\0p\0u\0t\0\x43\0t\0l\x1\0\0\0\0\xff\xff\xff\xff\0\0\x1P\0\xff\xff\xff\xfb\0\0\0\x12\0\x44\0o\0\x63\0k\0R\0x\0O\0p\0t\x1\0\0\0\0\xff\xff\xff\xff\0\0\x1g\0\a\xff\xff\xfb\0\0\0\xe\0\x44\0o\0\x63\0k\0\x46\0\x66\0t\x1\0\0\0\0\xff\xff\xff\xff\0\0\0\xc8\0\a\xff\xff\xfc\0\0\x1\xd1\0\0\0\xe5\0\0\0\xc3\0\xff\xff\xff\xfa\0\0\0\0\x2\0\0\0\x2\xfb\0\0\0\x12\0\x44\0o\0\x63\0k\0\x41\0u\0\x64\0i\0o\x1\0\0\0\0\xff\xff\xff\xff\0\0\0\xc3\0\xff\xff\xff\xfb\0\0\0\xe\0\x44\0o\0\x63\0k\0R\0\x44\0S\0\0\0\0\0\xff\xff\xff\xff\0\0\0h\0\xff\xff\xff\0\0\0\x3\0\0\0\0\0\0\0\0\xfc\x1\0\0\0\x1\xfb\0\0\0\x1a\0\x44\0o\0\x63\0k\0\x42\0o\0o\0k\0m\0\x61\0r\0k\0s\0\0\0\0\0\xff\xff\xff\xff\0\0\x1\x42\0\xff\xff\xff\0\0\x1\xbd\0\0\x2t\0\0\0\x1\0\0\0\x2\0\0\0\b\0\0\0\x2\xfc\0\0\0\x1\0\0\0\x2\0\0\0\x1\0\0\0\x16\0m\0\x61\0i\0n\0T\0o\0o\0l\0\x42\0\x61\0r\x1\0\0\0\0\xff\xff\xff\xff\0\0\0\0\0\0\0\0) + +[input] +dc_cancel=true +device="rtl=0" +frequency=154785000 +gains=@Variant(\0\0\0\b\0\0\0\x1\0\0\0\x6\0L\0N\0\x41\0\0\0\x2\0\0\x1P) +sample_rate=1800000 + +[receiver] +agc_off=true +demod=3 +filter_high_cut=2500 +filter_low_cut=-2500 +offset=-590400 +sql_level=-50 + +[remote_control] +allowed_hosts=localhost, 127.0.0.1, ::1 +enabled=true""" From 7ee5d92852a2fab8e40b471c19bfe097bc93ab09 Mon Sep 17 00:00:00 2001 From: Logan Cusano Date: Sat, 9 Apr 2022 01:21:33 -0400 Subject: [PATCH 11/32] forgot each item needed to be in the list, no spaces --- gqrxHandler.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gqrxHandler.py b/gqrxHandler.py index a2f1a52..222bc3d 100644 --- a/gqrxHandler.py +++ b/gqrxHandler.py @@ -109,7 +109,7 @@ class GQRXHandler(threading.Thread): if self.GQRXProc is not None: self.close_gqrx() - gqrx_kwargs = [f"-c drb_defaults.conf"] + gqrx_kwargs = [f"-c", "drb_defaults.conf"] self.logger.info(f"Resetting 'crashed' option in the GQRX config") From 5551aa63553b842d9b9529074ba0cd66e0be515a Mon Sep 17 00:00:00 2001 From: Logan Cusano Date: Sat, 9 Apr 2022 01:52:37 -0400 Subject: [PATCH 12/32] //WIP V3 Default Radio Settings Update - One location for default radio settings GQRX Changes - Default settings - Simpler check to see if GQRX is started - Working process handler --- BotResources.py | 11 +++++++++++ bot.py | 10 +++++----- gqrxHandler.py | 25 +++++++++++++++---------- op25Handler.py | 3 ++- 4 files changed, 33 insertions(+), 16 deletions(-) diff --git a/BotResources.py b/BotResources.py index 354ae74..bbb63a8 100644 --- a/BotResources.py +++ b/BotResources.py @@ -26,6 +26,17 @@ LOGGER = logging.getLogger('Discord_Radio_Bot.Bot_Resources') GQRX_BIN_LOCATION = "/usr/bin/" GQRX_BIN = "/usr/bin/gqrx" + +# Default radio settings +DEFAULT_RADIO_SETTINGS = { + 'profile_name': None, + 'freq': "104700000", + 'mode': "wfm", + 'squelch': 0, + 'noisegate_sensitivity': DEFAULT_NOISEGATE_THRESHOLD, +} + + def check_if_config_exists(): if exists('./config.ini'): config = configparser.SafeConfigParser() diff --git a/bot.py b/bot.py index 143a53a..16dcee2 100644 --- a/bot.py +++ b/bot.py @@ -42,11 +42,11 @@ class Bot(commands.Bot): _display_output_devices=False) # Init radio parameters - self.profile_name = None - self.freq = "104700000" - self.mode = "wfm" - self.squelch = 0 - self.noisegate_sensitivity = BotResources.DEFAULT_NOISEGATE_THRESHOLD + self.profile_name = BotResources.DEFAULT_RADIO_SETTINGS['profile_name'] + self.freq = BotResources.DEFAULT_RADIO_SETTINGS['freq'] + self.mode = BotResources.DEFAULT_RADIO_SETTINGS['mode'] + self.squelch = BotResources.DEFAULT_RADIO_SETTINGS['squelch'] + self.noisegate_sensitivity = BotResources.DEFAULT_RADIO_SETTINGS['noisegate_sensitivity'] # Init SDR Variables self.system_os_type = None diff --git a/gqrxHandler.py b/gqrxHandler.py index 222bc3d..f4e99ae 100644 --- a/gqrxHandler.py +++ b/gqrxHandler.py @@ -30,14 +30,15 @@ class GQRXHandler(threading.Thread): self.GQRXDir: str = GQRX_BIN_LOCATION self.GQRXEXE: str = shutil.which(GQRX_BIN) self.GQRXProc = None + self.GQRX_Started = False self.logger = logging.getLogger("Discord_Radio_Bot.GQRXHandler") self.Frequency = None - self.Mode = None - self.Frequency = None - self.Squelch = None + self.Mode = DEFAULT_RADIO_SETTINGS['mode'] + self.Frequency = DEFAULT_RADIO_SETTINGS['freq'] + self.Squelch = DEFAULT_RADIO_SETTINGS['squelch'] self.Start_GQRX = False self.Stop_GQRX = False @@ -68,11 +69,11 @@ class GQRXHandler(threading.Thread): sleep(.5) def set_gqrx_parameters(self, _frequency: str = False, _start: bool = False, _stop: bool = False, - _output_device_name: str = None, _fm_mode: str = None, _squelch: int = None, + _output_device_name: str = None, _fm_mode: str = None, _squelch: float = None, _hostname: str = None, _port: int = None, _start_dsp: bool = None): if _frequency: self.Frequency = _frequency - if self.GQRXProc: + if self.GQRX_Started: self.change_freq(_frequency) if _output_device_name: @@ -80,12 +81,12 @@ class GQRXHandler(threading.Thread): if _fm_mode: self.Mode = _fm_mode - if self.GQRXProc: + if self.GQRX_Started: self.change_mode(_fm_mode) if _squelch: self.Squelch = _squelch - if self.GQRXProc: + if self.GQRX_Started: self.change_squelch(_squelch) if _hostname: @@ -106,10 +107,10 @@ class GQRXHandler(threading.Thread): self.Stop_GQRX = _stop def open_gqrx(self): - if self.GQRXProc is not None: + if self.GQRX_Started: self.close_gqrx() - gqrx_kwargs = [f"-c", "drb_defaults.conf"] + gqrx_kwargs = [f"gqrx", "-c", "drb_defaults.conf"] self.logger.info(f"Resetting 'crashed' option in the GQRX config") @@ -119,13 +120,15 @@ class GQRXHandler(threading.Thread): self.logger.debug(f"GQRX Keyword Args: {gqrx_kwargs}") - self.GQRXProc = subprocess.Popen(gqrx_kwargs, executable=self.GQRXEXE, shell=False, cwd=self.GQRXDir) + self.GQRXProc = subprocess.Popen(gqrx_kwargs, executable=self.GQRXEXE, shell=False) while not self.tel_conn: self.create_telnet_connection() sleep(.5) self.logger.debug(f"Waiting for GQRX to start") + self.GQRX_Started = True + self.start_dsp() self.set_all_settings(_squelch=self.Squelch, _mode=self.Mode, _freq=self.Frequency) @@ -145,6 +148,8 @@ class GQRXHandler(threading.Thread): sleep(1) self.logger.debug(f"Waited {seconds_waited} seconds") seconds_waited += 1 + self.logger.debug("GQRX Closed") + self.GQRX_Started = False except Exception as e: self.logger.error(e) diff --git a/op25Handler.py b/op25Handler.py index 1c828cf..01e4006 100644 --- a/op25Handler.py +++ b/op25Handler.py @@ -3,6 +3,7 @@ import shutil import subprocess import threading import time +from BotResources import DEFAULT_RADIO_SETTINGS class OP25Handler(threading.Thread): @@ -12,7 +13,7 @@ class OP25Handler(threading.Thread): self.OP25EXE: str = shutil.which("/home/pi/op25/op25/gr-op25_repeater/apps/rx.py") self.OP25Proc = None - self.Frequency = None + self.Frequency = DEFAULT_RADIO_SETTINGS['freq'] self.HTTP_ENABLED = False From 2dabf1c98d8e55f5aa88dce72368a70a6f4a407d Mon Sep 17 00:00:00 2001 From: Logan Cusano Date: Sat, 9 Apr 2022 01:57:24 -0400 Subject: [PATCH 13/32] //WIP V3 GQRX Changes - Resetting tel_conn when closing GQRX --- gqrxHandler.py | 1 + 1 file changed, 1 insertion(+) diff --git a/gqrxHandler.py b/gqrxHandler.py index f4e99ae..9a61980 100644 --- a/gqrxHandler.py +++ b/gqrxHandler.py @@ -150,6 +150,7 @@ class GQRXHandler(threading.Thread): seconds_waited += 1 self.logger.debug("GQRX Closed") self.GQRX_Started = False + self.tel_conn = None except Exception as e: self.logger.error(e) From 63b37d14cb750461cd4b242215f2f853333a3f32 Mon Sep 17 00:00:00 2001 From: Logan Cusano Date: Sat, 9 Apr 2022 02:21:53 -0400 Subject: [PATCH 14/32] //WIP V3 Bot Changes - Improved handlers - Added new function to use the newly set or loaded settings - Any change to frequency, squelch, mode, or noisegate threshold will show no profile - The user is responsible for saving their changes Readme Changes - Update with notes on the bot change above --- README.md | 7 ++++++- bot.py | 38 ++++++++++++++++++++++++-------------- 2 files changed, 30 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 77a0b3f..d2c4708 100644 --- a/README.md +++ b/README.md @@ -23,4 +23,9 @@ Voicemeeter is **highly** recommended for this bot. See a detailed guide on how To change the audio source, simply delete the ```config.ini``` that was generated and restart the bot. It will re-do the setup and allow you to select a new device. -### [To-Do](https://git.vpn.cusano.net/Discord_Bot_Gang/Discord-Radio-Bot/src/branch/master/TODO.md) \ No newline at end of file +### [To-Do](https://git.vpn.cusano.net/Discord_Bot_Gang/Discord-Radio-Bot/src/branch/master/TODO.md) + + +**Notes for readme leter on** +- Users need to save profile after any change in discord +- \ No newline at end of file diff --git a/bot.py b/bot.py index 16dcee2..32dd755 100644 --- a/bot.py +++ b/bot.py @@ -173,8 +173,12 @@ class Bot(commands.Bot): f"{self.streamHandler.THRESHOLD} to {_threshold}") self.streamHandler.THRESHOLD = _threshold self.noisegate_sensitivity = _threshold - if self.sdr_started: - await self.set_activity() + + # Reset the profile name since we have made a change + self.profile_name = None + + # If the SDR is started, restart it with the updates + self.use_current_radio_config() # Add commands for GQRX and OP25 if self.Handler in BotResources.PDB_ACCEPTABLE_HANDLERS.keys(): @@ -225,13 +229,11 @@ class Bot(commands.Bot): await ctx.send(f"Ok {str(member).capitalize()}, I'm changing the mode to " f"{str(self.mode).upper()} and frequency to {self.freq}") - # Reset the profile name since we have made a change to the freq + # Reset the profile name since we have made a change self.profile_name = None # If the SDR is started, restart it with the updates - if self.sdr_started: - self.start_sdr() - await self.set_activity() + self.use_current_radio_config() else: await ctx.send(f"{str(member).capitalize()}, {mode} is not valid." f" You may only enter {self.possible_modes}") @@ -254,9 +256,11 @@ class Bot(commands.Bot): self.squelch = squelch await ctx.send(f"Ok {str(member).capitalize()}, I'm changing the squelch to {self.squelch}") + # Reset the profile name since we have made a change + self.profile_name = None + # If the SDR is started, restart it with the updates - if self.sdr_started: - self.start_sdr() + self.use_current_radio_config() # Hidden admin commands @self.command(name='saveprofile', hidden=True) @@ -505,8 +509,19 @@ class Bot(commands.Bot): self.profile_name = profile_name + self.use_current_radio_config() + + def use_current_radio_config(self): if self.sdr_started: - self.start_sdr() + # Set the loaded profile settings into GQRX + if self.Handler == "gqrx": + self.GQRXHandler.set_gqrx_parameters(_frequency=self.freq, _squelch=self.squelch, + _fm_mode=self.mode) + # Restart OP25 to use the loaded profile + if self.Handler == "op25": + self.start_sdr() + + # Set the activity to reflect the loaded profile await self.set_activity() # Load a saved profile into the current settings @@ -528,11 +543,6 @@ class Bot(commands.Bot): f"{BotResources.DEFAULT_NOISEGATE_THRESHOLD}") self.noisegate_sensitivity = BotResources.DEFAULT_NOISEGATE_THRESHOLD await self.save_radio_config(self.profile_name) - - if self.sdr_started: - self.start_sdr() - await self.set_activity() - return True else: return False From dbbd5b6fe3c10a06095ab27c99c07c4519f066f5 Mon Sep 17 00:00:00 2001 From: Logan Cusano Date: Sat, 9 Apr 2022 02:23:46 -0400 Subject: [PATCH 15/32] //WIP V3 Bot Changes - Awaiting new async 'use_current_radio_config' function --- bot.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/bot.py b/bot.py index 32dd755..1693d24 100644 --- a/bot.py +++ b/bot.py @@ -178,7 +178,7 @@ class Bot(commands.Bot): self.profile_name = None # If the SDR is started, restart it with the updates - self.use_current_radio_config() + await self.use_current_radio_config() # Add commands for GQRX and OP25 if self.Handler in BotResources.PDB_ACCEPTABLE_HANDLERS.keys(): @@ -233,7 +233,7 @@ class Bot(commands.Bot): self.profile_name = None # If the SDR is started, restart it with the updates - self.use_current_radio_config() + await self.use_current_radio_config() else: await ctx.send(f"{str(member).capitalize()}, {mode} is not valid." f" You may only enter {self.possible_modes}") @@ -260,7 +260,7 @@ class Bot(commands.Bot): self.profile_name = None # If the SDR is started, restart it with the updates - self.use_current_radio_config() + await self.use_current_radio_config() # Hidden admin commands @self.command(name='saveprofile', hidden=True) @@ -509,9 +509,9 @@ class Bot(commands.Bot): self.profile_name = profile_name - self.use_current_radio_config() + await self.use_current_radio_config() - def use_current_radio_config(self): + async def use_current_radio_config(self): if self.sdr_started: # Set the loaded profile settings into GQRX if self.Handler == "gqrx": From 458ab5be958adf5a808805340c6d255ac11377df Mon Sep 17 00:00:00 2001 From: Logan Cusano Date: Sat, 9 Apr 2022 02:25:46 -0400 Subject: [PATCH 16/32] //WIP V3 Bot Changes - Never used new radio config function when loading config --- bot.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bot.py b/bot.py index 1693d24..94e4fab 100644 --- a/bot.py +++ b/bot.py @@ -543,6 +543,8 @@ class Bot(commands.Bot): f"{BotResources.DEFAULT_NOISEGATE_THRESHOLD}") self.noisegate_sensitivity = BotResources.DEFAULT_NOISEGATE_THRESHOLD await self.save_radio_config(self.profile_name) + + await self.use_current_radio_config() return True else: return False From a483f83b4b9147fc8df1529ab5e27bff0de24221 Mon Sep 17 00:00:00 2001 From: Logan Cusano Date: Sat, 9 Apr 2022 02:36:48 -0400 Subject: [PATCH 17/32] //WIP V3 Bot Changes - Increased loop delay when waiting for GQRX to start Noisegate Change - Display whether the noisegate is active or not in the logs --- NoiseGatev2.py | 5 ++++- gqrxHandler.py | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/NoiseGatev2.py b/NoiseGatev2.py index 96a8db0..cae6880 100644 --- a/NoiseGatev2.py +++ b/NoiseGatev2.py @@ -167,7 +167,10 @@ class NoiseGateStream(discord.AudioSource): buffer_decibel = 20 * math.log10(buffer_rms) if self.process_set_count % 10 == 0: - LOGGER.debug(f"{buffer_decibel} db") + if buffer_decibel >= self.stream.THRESHOLD: + LOGGER.debug(f"[Noisegate Open] {buffer_decibel} db") + else: + LOGGER.debug(f"[Noisegate Closed] {buffer_decibel} db") if buffer_decibel >= self.stream.THRESHOLD: self.NG_fadeout_count = self.NG_fadeout diff --git a/gqrxHandler.py b/gqrxHandler.py index 9a61980..57f99e7 100644 --- a/gqrxHandler.py +++ b/gqrxHandler.py @@ -124,7 +124,7 @@ class GQRXHandler(threading.Thread): while not self.tel_conn: self.create_telnet_connection() - sleep(.5) + sleep(2) self.logger.debug(f"Waiting for GQRX to start") self.GQRX_Started = True From cccd974adc63e23b179711f82e3bb862a1c59d2a Mon Sep 17 00:00:00 2001 From: Logan Cusano Date: Sat, 9 Apr 2022 03:39:45 -0400 Subject: [PATCH 18/32] //WIP V3 GQRX Changes - Changed repeating log entry to debug --- gqrxHandler.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gqrxHandler.py b/gqrxHandler.py index 57f99e7..6fc75ec 100644 --- a/gqrxHandler.py +++ b/gqrxHandler.py @@ -156,7 +156,7 @@ class GQRXHandler(threading.Thread): self.logger.error(e) def create_telnet_connection(self): - self.logger.info("Creating connection") + self.logger.debug("Creating connection") try: self.tel_conn = Telnet(self.hostname, self.port) self.tel_conn.open(self.hostname, self.port) From b7f09397875d83dc51bad8af93b43c3e77fe3888 Mon Sep 17 00:00:00 2001 From: Logan Cusano Date: Sat, 9 Apr 2022 04:32:12 -0400 Subject: [PATCH 19/32] //WIP V3 GQRX Changes - Sending output to devnull, except for error --- op25Handler.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/op25Handler.py b/op25Handler.py index 01e4006..be20bfc 100644 --- a/op25Handler.py +++ b/op25Handler.py @@ -71,7 +71,8 @@ class OP25Handler(threading.Thread): self.logger.debug(f"OP25 Keyword Args: {p25_kwargs}") - self.OP25Proc = subprocess.Popen(p25_kwargs, executable=self.OP25EXE, shell=False, cwd=self.OP25Dir) + self.OP25Proc = subprocess.Popen(p25_kwargs, executable=self.OP25EXE, shell=False, cwd=self.OP25Dir, + stdin=subprocess.DEVNULL, stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT) def close_op25(self): self.logger.info(f"Closing OP25") From 3837f7abd6a018bb187f74757337003b8d2385fc Mon Sep 17 00:00:00 2001 From: Logan Cusano Date: Sat, 9 Apr 2022 21:27:49 -0400 Subject: [PATCH 20/32] //WIP V3 Update todo --- TODO.md | 1 + 1 file changed, 1 insertion(+) diff --git a/TODO.md b/TODO.md index 4b281c7..40383b2 100644 --- a/TODO.md +++ b/TODO.md @@ -3,6 +3,7 @@ ### Main Development #### Core - [ ] Add new handlers for GQRX: https://github.com/gqrx-sdr/gqrx/blob/master/resources/remote-control.txt +- [ ] Add logging for Elasticstack https://www.elastic.co/guide/en/ecs-logging/python/master/installation.html - [ ] Add a process handler to start/stop gqrx - [ ] Fix the bug where they *disconnect* after a period of time and must be manually moved out and back in to hear them - *May* have been fixed with the noise gate? From 35e19ee83fa4c662d1511d6edbb9b421bd92141d Mon Sep 17 00:00:00 2001 From: Logan Cusano Date: Sat, 9 Apr 2022 21:39:44 -0400 Subject: [PATCH 21/32] //WIP v3 Clear Messages Changes - New approach --- modules/ClearChannelMessages/cog.py | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/modules/ClearChannelMessages/cog.py b/modules/ClearChannelMessages/cog.py index e902035..ed55ee4 100644 --- a/modules/ClearChannelMessages/cog.py +++ b/modules/ClearChannelMessages/cog.py @@ -1,6 +1,9 @@ +import logging from discord.ext import commands import asyncio +LOGGER = logging.getLogger("Discord_Radio_Bot.LinkCop") + class ClearMessages(commands.Cog): def __init__(self, bot): @@ -8,23 +11,19 @@ class ClearMessages(commands.Cog): @commands.command() async def clear(self, ctx, amount=0): - if amount == 0: - fail = await ctx.send("Please enter an amount to delete!") - await asyncio.sleep(6) - await fail.delete() + member = ctx.author.display_name + LOGGER.info(f"Clear {amount} messages requested by {member}") + authors = {} - if amount < 3: - await ctx.channel.purge(limit=amount) - sucess = await ctx.send( - f"{amount} messages has been deleted ") # sending success msg - await asyncio.sleep(6) # wait 6 seconds - await sucess.delete() # deleting the success msg + async for message in ctx.channel.history(limit=amount + 1): + if message.author not in authors: + authors[message.author] = 1 + else: + authors[message.author] += 1 + await message.delete() - else: - if amount == 0: - fail = await ctx.send("Please enter an amount to delete!") - await asyncio.sleep(6) - await fail.delete() + msg = "\n".join([f"{author}:{amount}" for author, amount in authors.items()]) + await ctx.channel.send(msg) def setup(bot: commands.Bot): From 8d090c5c674380b59155eae9ae3ca6f46b043818 Mon Sep 17 00:00:00 2001 From: Logan Cusano Date: Sat, 9 Apr 2022 21:58:34 -0400 Subject: [PATCH 22/32] //WIP v3 Clear Messages Changes - Better logging - Better output --- modules/ClearChannelMessages/cog.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/modules/ClearChannelMessages/cog.py b/modules/ClearChannelMessages/cog.py index ed55ee4..df23fe4 100644 --- a/modules/ClearChannelMessages/cog.py +++ b/modules/ClearChannelMessages/cog.py @@ -1,6 +1,5 @@ import logging from discord.ext import commands -import asyncio LOGGER = logging.getLogger("Discord_Radio_Bot.LinkCop") @@ -12,17 +11,24 @@ class ClearMessages(commands.Cog): @commands.command() async def clear(self, ctx, amount=0): member = ctx.author.display_name + mtn_member = f"<@{member}>" LOGGER.info(f"Clear {amount} messages requested by {member}") - authors = {} - async for message in ctx.channel.history(limit=amount + 1): + authors = {} + async for message in ctx.channel.history(limit=amount): if message.author not in authors: authors[message.author] = 1 else: authors[message.author] += 1 await message.delete() - msg = "\n".join([f"{author}:{amount}" for author, amount in authors.items()]) + msg = f"{mtn_member}, I deleted {sum(authors.values())} messages\n" + LOGGER.debug(f"Deleted {sum(authors.values())} messages from {ctx.message.channel}") + + for author in authors.keys(): + msg += f"\t{author}: {authors[author]}" + LOGGER.debug(f"Deleted {authors[author]} messages from {author}") + await ctx.channel.send(msg) From 8af7a70b652911ea9ffdbecebadbee470458f296 Mon Sep 17 00:00:00 2001 From: Logan Cusano Date: Sat, 9 Apr 2022 22:02:04 -0400 Subject: [PATCH 23/32] //WIP v3 Clear Messages Changes - Mentioning user ID not name --- modules/ClearChannelMessages/cog.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/modules/ClearChannelMessages/cog.py b/modules/ClearChannelMessages/cog.py index df23fe4..6d0f8e9 100644 --- a/modules/ClearChannelMessages/cog.py +++ b/modules/ClearChannelMessages/cog.py @@ -11,7 +11,8 @@ class ClearMessages(commands.Cog): @commands.command() async def clear(self, ctx, amount=0): member = ctx.author.display_name - mtn_member = f"<@{member}>" + member_id = ctx.author.id + mtn_member = f"<@{member_id}>" LOGGER.info(f"Clear {amount} messages requested by {member}") authors = {} @@ -26,7 +27,7 @@ class ClearMessages(commands.Cog): LOGGER.debug(f"Deleted {sum(authors.values())} messages from {ctx.message.channel}") for author in authors.keys(): - msg += f"\t{author}: {authors[author]}" + msg += f"\t{author}: {authors[author]}\n" LOGGER.debug(f"Deleted {authors[author]} messages from {author}") await ctx.channel.send(msg) From b0d83def350fd711093d158c454e172732773f0a Mon Sep 17 00:00:00 2001 From: Logan Cusano Date: Sat, 9 Apr 2022 22:03:52 -0400 Subject: [PATCH 24/32] //WIP v3 Clear Messages Changes - No "#0000" in username output --- modules/ClearChannelMessages/cog.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/ClearChannelMessages/cog.py b/modules/ClearChannelMessages/cog.py index 6d0f8e9..379a694 100644 --- a/modules/ClearChannelMessages/cog.py +++ b/modules/ClearChannelMessages/cog.py @@ -27,7 +27,7 @@ class ClearMessages(commands.Cog): LOGGER.debug(f"Deleted {sum(authors.values())} messages from {ctx.message.channel}") for author in authors.keys(): - msg += f"\t{author}: {authors[author]}\n" + msg += f"\t{str(author).split('#', 1)[0]}: {authors[author]}\n" LOGGER.debug(f"Deleted {authors[author]} messages from {author}") await ctx.channel.send(msg) From bfb049e268786fc49466bb876f7bf23c9b71c997 Mon Sep 17 00:00:00 2001 From: Logan Cusano Date: Sat, 9 Apr 2022 22:05:32 -0400 Subject: [PATCH 25/32] //WIP v3 Clear Messages Changes - Default clear to 2 messages (instantiation and the previous message) --- modules/ClearChannelMessages/cog.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/ClearChannelMessages/cog.py b/modules/ClearChannelMessages/cog.py index 379a694..f323663 100644 --- a/modules/ClearChannelMessages/cog.py +++ b/modules/ClearChannelMessages/cog.py @@ -9,9 +9,10 @@ class ClearMessages(commands.Cog): self.Bot = bot @commands.command() - async def clear(self, ctx, amount=0): + async def clear(self, ctx, amount=2): member = ctx.author.display_name member_id = ctx.author.id + mtn_member = f"<@{member_id}>" LOGGER.info(f"Clear {amount} messages requested by {member}") From dcf0de835198d2c8fa05237e6dfd61545a53360e Mon Sep 17 00:00:00 2001 From: Logan Cusano Date: Sat, 9 Apr 2022 22:09:24 -0400 Subject: [PATCH 26/32] //WIP v3 Clear Messages Changes - Added help message --- modules/ClearChannelMessages/cog.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/modules/ClearChannelMessages/cog.py b/modules/ClearChannelMessages/cog.py index f323663..a178033 100644 --- a/modules/ClearChannelMessages/cog.py +++ b/modules/ClearChannelMessages/cog.py @@ -8,7 +8,12 @@ class ClearMessages(commands.Cog): def __init__(self, bot): self.Bot = bot - @commands.command() + @commands.command(name='displayprofiles', + help="Use this command to clear a given number of messages from the channel it is called in.\n" + "Example command:\n" + "\t@ clear\n" + "\t@ clear 10", + breif="Clear x messages in the channel it's called in") async def clear(self, ctx, amount=2): member = ctx.author.display_name member_id = ctx.author.id @@ -24,7 +29,7 @@ class ClearMessages(commands.Cog): authors[message.author] += 1 await message.delete() - msg = f"{mtn_member}, I deleted {sum(authors.values())} messages\n" + msg = f"{mtn_member}, I deleted {sum(authors.values())} messages from {len(authors.keys())} users:\n" LOGGER.debug(f"Deleted {sum(authors.values())} messages from {ctx.message.channel}") for author in authors.keys(): From 9dba89a60b45aed633ad1c62ba73d936963f8c35 Mon Sep 17 00:00:00 2001 From: Logan Cusano Date: Sat, 9 Apr 2022 22:14:21 -0400 Subject: [PATCH 27/32] //WIP v3 Clear Messages Changes - Check for negative numbers... Gino --- modules/ClearChannelMessages/cog.py | 36 ++++++++++++++++------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/modules/ClearChannelMessages/cog.py b/modules/ClearChannelMessages/cog.py index a178033..5dfabe3 100644 --- a/modules/ClearChannelMessages/cog.py +++ b/modules/ClearChannelMessages/cog.py @@ -14,29 +14,33 @@ class ClearMessages(commands.Cog): "\t@ clear\n" "\t@ clear 10", breif="Clear x messages in the channel it's called in") - async def clear(self, ctx, amount=2): + async def clear(self, ctx, amount: int = 2): member = ctx.author.display_name member_id = ctx.author.id - mtn_member = f"<@{member_id}>" - LOGGER.info(f"Clear {amount} messages requested by {member}") - authors = {} - async for message in ctx.channel.history(limit=amount): - if message.author not in authors: - authors[message.author] = 1 - else: - authors[message.author] += 1 - await message.delete() + if amount < 0: + ctx.send(f"{member}, the number needs to be positive...") - msg = f"{mtn_member}, I deleted {sum(authors.values())} messages from {len(authors.keys())} users:\n" - LOGGER.debug(f"Deleted {sum(authors.values())} messages from {ctx.message.channel}") + else: + LOGGER.info(f"Clear {amount} messages requested by {member}") - for author in authors.keys(): - msg += f"\t{str(author).split('#', 1)[0]}: {authors[author]}\n" - LOGGER.debug(f"Deleted {authors[author]} messages from {author}") + authors = {} + async for message in ctx.channel.history(limit=amount): + if message.author not in authors: + authors[message.author] = 1 + else: + authors[message.author] += 1 + await message.delete() - await ctx.channel.send(msg) + msg = f"{mtn_member}, I deleted {sum(authors.values())} messages from {len(authors.keys())} users:\n" + LOGGER.debug(f"Deleted {sum(authors.values())} messages from {ctx.message.channel}") + + for author in authors.keys(): + msg += f"\t{str(author).split('#', 1)[0]}: {authors[author]}\n" + LOGGER.debug(f"Deleted {authors[author]} messages from {author}") + + await ctx.send(msg) def setup(bot: commands.Bot): From 4d5c1183d6bb5c4843abab06d7f0c3cd58795544 Mon Sep 17 00:00:00 2001 From: Logan Cusano Date: Sat, 9 Apr 2022 22:15:37 -0400 Subject: [PATCH 28/32] //WIP v3 Clear Messages Changes - Bug --- modules/ClearChannelMessages/cog.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/modules/ClearChannelMessages/cog.py b/modules/ClearChannelMessages/cog.py index 5dfabe3..137884c 100644 --- a/modules/ClearChannelMessages/cog.py +++ b/modules/ClearChannelMessages/cog.py @@ -8,12 +8,12 @@ class ClearMessages(commands.Cog): def __init__(self, bot): self.Bot = bot - @commands.command(name='displayprofiles', - help="Use this command to clear a given number of messages from the channel it is called in.\n" - "Example command:\n" - "\t@ clear\n" - "\t@ clear 10", - breif="Clear x messages in the channel it's called in") + @commands.command(name='clear', + help="Use this command to clear a given number of messages from the channel it is called in.\n" + "Example command:\n" + "\t@ clear\n" + "\t@ clear 10", + breif="Clear x messages in the channel it's called in") async def clear(self, ctx, amount: int = 2): member = ctx.author.display_name member_id = ctx.author.id From 0db4f62afc8a5087e52b76c7b46579d78af9fa62 Mon Sep 17 00:00:00 2001 From: Logan Cusano Date: Sat, 9 Apr 2022 22:22:44 -0400 Subject: [PATCH 29/32] //WIP v3 Clear Messages Changes - Bug - More error checking - Limit the user to 100 messages - More help text --- modules/ClearChannelMessages/cog.py | 47 ++++++++++++++++------------- 1 file changed, 26 insertions(+), 21 deletions(-) diff --git a/modules/ClearChannelMessages/cog.py b/modules/ClearChannelMessages/cog.py index 137884c..1b17f49 100644 --- a/modules/ClearChannelMessages/cog.py +++ b/modules/ClearChannelMessages/cog.py @@ -10,37 +10,42 @@ class ClearMessages(commands.Cog): @commands.command(name='clear', help="Use this command to clear a given number of messages from the channel it is called in.\n" + "There is a limit of 100 messages. Please be patient, it may take a while to process a large request." "Example command:\n" "\t@ clear\n" "\t@ clear 10", breif="Clear x messages in the channel it's called in") - async def clear(self, ctx, amount: int = 2): + async def clear(self, ctx, amount=2): member = ctx.author.display_name member_id = ctx.author.id mtn_member = f"<@{member_id}>" - if amount < 0: - ctx.send(f"{member}, the number needs to be positive...") + if isinstance(amount, int): + if not amount > 0: + ctx.channel.send(f"{member}, the number needs to be positive...") + + else: + LOGGER.info(f"Clear {amount} messages requested by {member}") + + authors = {} + async for message in ctx.channel.history(limit=amount): + if message.author not in authors: + authors[message.author] = 1 + else: + authors[message.author] += 1 + await message.delete() + + msg = f"{mtn_member}, I deleted {sum(authors.values())} messages from {len(authors.keys())} users:\n" + LOGGER.debug(f"Deleted {sum(authors.values())} messages from {ctx.message.channel}") + + for author in authors.keys(): + msg += f"\t{str(author).split('#', 1)[0]}: {authors[author]}\n" + LOGGER.debug(f"Deleted {authors[author]} messages from {author}") + + await ctx.channel.send(msg) else: - LOGGER.info(f"Clear {amount} messages requested by {member}") - - authors = {} - async for message in ctx.channel.history(limit=amount): - if message.author not in authors: - authors[message.author] = 1 - else: - authors[message.author] += 1 - await message.delete() - - msg = f"{mtn_member}, I deleted {sum(authors.values())} messages from {len(authors.keys())} users:\n" - LOGGER.debug(f"Deleted {sum(authors.values())} messages from {ctx.message.channel}") - - for author in authors.keys(): - msg += f"\t{str(author).split('#', 1)[0]}: {authors[author]}\n" - LOGGER.debug(f"Deleted {authors[author]} messages from {author}") - - await ctx.send(msg) + ctx.channel.send(f"{member}, you should check out the 'help' section...") def setup(bot: commands.Bot): From e4e04e429f236ea37776b815680f84b077c83254 Mon Sep 17 00:00:00 2001 From: Logan Cusano Date: Sat, 9 Apr 2022 22:27:26 -0400 Subject: [PATCH 30/32] //WIP v3 GQRX Config Template - Added switch to allow AGC --- templates/gqrx_config_template.py | 1 - 1 file changed, 1 deletion(-) diff --git a/templates/gqrx_config_template.py b/templates/gqrx_config_template.py index 501e31a..bf5af44 100644 --- a/templates/gqrx_config_template.py +++ b/templates/gqrx_config_template.py @@ -30,7 +30,6 @@ gains=@Variant(\0\0\0\b\0\0\0\x1\0\0\0\x6\0L\0N\0\x41\0\0\0\x2\0\0\x1P) sample_rate=1800000 [receiver] -agc_off=true demod=3 filter_high_cut=2500 filter_low_cut=-2500 From 62f9e1abaa457de0663b76a549b11f56dbb5f377 Mon Sep 17 00:00:00 2001 From: Logan Cusano Date: Sat, 9 Apr 2022 22:34:56 -0400 Subject: [PATCH 31/32] //WIP v3 GQRX Changes - Ensure AGC is enabled whenever the bot starts --- gqrxHandler.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/gqrxHandler.py b/gqrxHandler.py index 6fc75ec..a17f60c 100644 --- a/gqrxHandler.py +++ b/gqrxHandler.py @@ -18,11 +18,20 @@ def reset_crashed(_config_path): with open(_config_path, 'w') as config_file: config.write(config_file) return True - else: return False +def enable_agc(_config_path): + config = configparser.SafeConfigParser() + config.read(_config_path) + if config.has_option('receiver', 'agc_off'): + config.remove_option('receiver', 'agc_off') + with open(_config_path, 'w') as config_file: + config.write(config_file) + return True + + class GQRXHandler(threading.Thread): def __init__(self): super().__init__() @@ -206,6 +215,9 @@ class GQRXHandler(threading.Thread): def reset_or_create_config(self): if self.GQRX_Config_Path.is_file(): + self.logger.debug(f"Enabling AGC in the GQRX config") + enable_agc(_config_path=self.GQRX_Config_Path) + self.logger.debug(f"GQRX Config exists, resetting 'crashed' setting") reset_crashed(_config_path=self.GQRX_Config_Path) else: From a094ba581d2211b43a5204811e92f7db5a428012 Mon Sep 17 00:00:00 2001 From: Logan Cusano Date: Sun, 10 Apr 2022 13:53:59 -0400 Subject: [PATCH 32/32] //WIP v3 GQRX Changes - Better error handling; GQRX config dupes some options for an unknown reason --- gqrxHandler.py | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/gqrxHandler.py b/gqrxHandler.py index a17f60c..c3afbd1 100644 --- a/gqrxHandler.py +++ b/gqrxHandler.py @@ -1,3 +1,4 @@ +import configparser import shutil import logging import threading @@ -213,19 +214,26 @@ class GQRXHandler(threading.Thread): self.change_freq(_freq) self.change_squelch(_squelch) + def creat_config(self): + from templates.gqrx_config_template import drb_defaults + config = drb_defaults + try: + with open(self.GQRX_Config_Path, 'w+') as config_file: + config_file.write(config) + except OSError as err: + self.logger.error(err) + def reset_or_create_config(self): if self.GQRX_Config_Path.is_file(): - self.logger.debug(f"Enabling AGC in the GQRX config") - enable_agc(_config_path=self.GQRX_Config_Path) + try: + self.logger.debug(f"Enabling AGC in the GQRX config") + enable_agc(_config_path=self.GQRX_Config_Path) - self.logger.debug(f"GQRX Config exists, resetting 'crashed' setting") - reset_crashed(_config_path=self.GQRX_Config_Path) + self.logger.debug(f"GQRX Config exists, resetting 'crashed' setting") + reset_crashed(_config_path=self.GQRX_Config_Path) + except configparser.DuplicateOptionError as err: + self.logger.warning(err) + self.creat_config() else: self.logger.debug(f"GQRX config does not exist, creating it from template") - from templates.gqrx_config_template import drb_defaults - config = drb_defaults - try: - with open(self.GQRX_Config_Path, 'w+') as config_file: - config_file.write(config) - except OSError as err: - self.logger.error(err) + self.creat_config()