diff --git a/owrx/controllers/settings.py b/owrx/controllers/settings.py
index 7b26601..7327f9f 100644
--- a/owrx/controllers/settings.py
+++ b/owrx/controllers/settings.py
@@ -23,7 +23,9 @@ class Input(ABC):
{infotext}
- """.format(id=self.id, label=self.label, input=input, infotext=infotext)
+ """.format(
+ id=self.id, label=self.label, input=input, infotext=infotext
+ )
def input_classes(self):
return " ".join(["form-control", "form-control-sm"])
@@ -43,7 +45,9 @@ class TextInput(Input):
def render_input(self, value):
return """
- """.format(id=self.id, label=self.label, classes=self.input_classes(), value=value)
+ """.format(
+ id=self.id, label=self.label, classes=self.input_classes(), value=value
+ )
class LocationInput(Input):
@@ -56,7 +60,9 @@ class TextAreaInput(Input):
def render_input(self, value):
return """
- """.format(id=self.id, classes=self.input_classes(), value=value)
+ """.format(
+ id=self.id, classes=self.input_classes(), value=value
+ )
class CheckboxInput(Input):
@@ -72,7 +78,9 @@ class CheckboxInput(Input):
{checkboxText}
- """.format(id=self.id, classes=self.input_classes(), checked="checked" if value else "", checkboxText=self.checkboxText)
+ """.format(
+ id=self.id, classes=self.input_classes(), checked="checked" if value else "", checkboxText=self.checkboxText
+ )
def input_classes(self):
return " ".join(["form-check", "form-control-sm"])
@@ -81,6 +89,33 @@ class CheckboxInput(Input):
return {self.id: self.id in data and data[self.id][0] == "on"}
+class DropdownOption(object):
+ def __init__(self, value, text):
+ self.value = value
+ self.text = text
+
+
+class DropdownInput(Input):
+ def __init__(self, id, label, options, infotext = None):
+ super().__init__(id, label, infotext=infotext)
+ self.options = options
+
+ def render_input(self, value):
+ return """
+
+ """.format(classes=self.input_classes(), id=self.id, options=self.render_options(value))
+
+ def render_options(self, value):
+ options = [
+ """
+
+ """.format(
+ text=o.text, value=o.value, selected="selected" if o.value == value else ""
+ ) for o in self.options
+ ]
+ return "".join(options)
+
+
class Section(object):
def __init__(self, title, *inputs):
self.title = title
@@ -98,7 +133,9 @@ class Section(object):
{inputs}
- """.format(title=self.title, inputs=self.render_inputs())
+ """.format(
+ title=self.title, inputs=self.render_inputs()
+ )
def parse(self, data):
return {k: v for i in self.inputs for k, v in i.parse(data).items()}
@@ -107,7 +144,7 @@ class Section(object):
class SettingsController(AdminController):
sections = [
Section(
- "General Settings",
+ "General settings",
TextInput("receiver_name", "Receiver name"),
TextInput("receiver_location", "Receiver location"),
TextInput("receiver_asl", "Receiver elevation", infotext="Elevation in meters above mean see level"),
@@ -116,9 +153,141 @@ class SettingsController(AdminController):
TextInput("photo_title", "Photo title"),
TextAreaInput("photo_desc", "Photo description"),
),
+ Section(
+ "Waterfall settings",
+ TextInput(
+ "fft_fps",
+ "FFT frames per second",
+ infotext="This setting specifies how many lines are being added to the waterfall per second. "
+ + "Higher values will give you a faster waterfall, but will also use more CPU.",
+ ),
+ TextInput("fft_size", "FFT size"),
+ TextInput(
+ "fft_voverlap_factor",
+ "FFT vertical overlap factor",
+ infotext="If fft_voverlap_factor is above 0, multiple FFTs will be used for creating a line on the "
+ + "diagram.",
+ ),
+ TextInput("waterfall_min_level", "Lowest waterfall level"),
+ TextInput("waterfall_max_level", "Highest waterfall level"),
+ ),
+ Section(
+ "Compression",
+ DropdownInput("audio_compression", "Audio compression", options=[
+ DropdownOption("adpcm", "ADPCM"),
+ DropdownOption("none", "None"),
+ ]),
+ DropdownInput("fft_compression", "Waterfall compression", options=[
+ DropdownOption("adpcm", "ADPCM"),
+ DropdownOption("none", "None"),
+ ]),
+ ),
+ Section(
+ "Digimodes",
+ CheckboxInput("digimodes_enable", "", checkboxText="Enable Digimodes"),
+ TextInput("digimodes_fft_size", "Digimodes FFT size"),
+ ),
+ Section(
+ "Digital voice",
+ TextInput(
+ "digital_voice_unvoiced_quality",
+ "Quality of unvoiced sounds in synthesized voice",
+ infotext="Determines the quality, and thus the cpu usage, for the ambe codec used by digital voice"
+ + "modes.
If you're running on a Raspi (up to 3B+) you should leave this set at 1"
+ ),
+ CheckboxInput(
+ "digital_voice_dmr_id_lookup",
+ "DMR id lookup",
+ checkboxText="Enable lookup of DMR ids in the radioid database to show callsigns and names"
+ ),
+ ),
+ Section(
+ "Experimental pipe settings",
+ CheckboxInput(
+ "csdr_dynamic_bufsize",
+ "",
+ checkboxText="Enable dynamic buffer sizes",
+ infotext="This allows you to change the buffering mode of csdr."
+ ),
+ CheckboxInput(
+ "csdr_print_bufsizes",
+ "",
+ checkboxText="Print buffer sizez",
+ infotext="This prints the buffer sizes used for csdr processes."
+ ),
+ CheckboxInput(
+ "csdr_through",
+ "",
+ checkboxText="Print throughput",
+ infotext="Enabling this will print out how much data is going into the DSP chains."
+ ),
+ ),
+ Section(
+ "Map settings",
+ TextInput(
+ "google_maps_api_key",
+ "Google Maps API key",
+ infotext="Google Maps requires an API key, check out "
+ + ''
+ + "their documentation on how to obtain one."
+ ),
+ TextInput(
+ "map_position_retention_time",
+ "Map retention time",
+ infotext="Unit is seconds
Specifies how log markers / grids will remain visible on the map"
+ ),
+ ),
+ Section(
+ "WSJT-X settings",
+ TextInput("wsjt_queue_workers", "Number of WSJT decoding workers"),
+ TextInput("wsjt_queue_length", "Maximum length of WSJT job queue"),
+ TextInput(
+ "wsjt_decoding_depth",
+ "WSJT decoding depth",
+ infotext="A higher decoding depth will allow more results, but will also consume more cpu"
+ )
+ ),
+ Section(
+ "Background decoding",
+ CheckboxInput("services_enabled", "Service", checkboxText="Enable background decoding services"),
+ ),
+ Section(
+ "APRS settings",
+ TextInput(
+ "aprs_callsign",
+ "APRS callsign",
+ infotext="This callsign will be used to send data to the APRS-IS network"
+ ),
+ CheckboxInput(
+ "aprs_igate_enabled",
+ "APRS I-Gate",
+ checkboxText="Enable APRS receive-only I-Gate"
+ ),
+ TextInput("aprs_igate_server", "APRS-IS server"),
+ TextInput("aprs_igate_password", "APRS-IS network password"),
+ CheckboxInput(
+ "aprs_igate_beacon",
+ "APRS beacon",
+ checkboxText="Send the receiver position to the APRS-IS network",
+ infotext="Please check that your receiver location is setup correctly"
+ ),
+ ),
+ Section(
+ "pskreporter settings",
+ CheckboxInput("pskreporter_enabled", "Reporting", checkboxText="Enable sending spots to pskreporter.info"),
+ TextInput(
+ "pskreporter_callsign",
+ "pskreporter callsign",
+ infotext="This callsign will be used to send spots to pskreporter.info"
+ ),
+ ),
Section(
"sdr.hu",
- TextInput("sdrhu_key", "sdr.hu key", infotext="Please obtain your personal key on sdr.hu"),
+ TextInput(
+ "sdrhu_key",
+ "sdr.hu key",
+ infotext='Please obtain your personal key on sdr.hu',
+ ),
CheckboxInput("sdrhu_public_listing", "List on sdr.hu", "List msy receiver on sdr.hu"),
TextInput("server_hostname", "Hostname"),
),
@@ -133,7 +302,9 @@ class SettingsController(AdminController):
- """.format(sections=sections)
+ """.format(
+ sections=sections
+ )
def indexAction(self):
self.serve_template("admin.html", **self.template_variables())