implement profile editing page

This commit is contained in:
Jakob Ketterl 2021-02-23 18:32:23 +01:00
parent ed258cc9a0
commit c5df6a1527
11 changed files with 120 additions and 16 deletions

View File

@ -5,6 +5,7 @@ from owrx.source import SdrDeviceDescription, SdrDeviceDescriptionMissing
from owrx.config import Config from owrx.config import Config
from urllib.parse import quote, unquote from urllib.parse import quote, unquote
from owrx.sdr import SdrService from owrx.sdr import SdrService
from abc import ABCMeta
class SdrDeviceListController(AuthorizationMixin, WebpageController): class SdrDeviceListController(AuthorizationMixin, WebpageController):
@ -52,14 +53,11 @@ class SdrDeviceListController(AuthorizationMixin, WebpageController):
self.serve_template("settings/general.html", **self.template_variables()) self.serve_template("settings/general.html", **self.template_variables())
class SdrDeviceController(SettingsFormController): class SdrFormController(SettingsFormController, metaclass=ABCMeta):
def __init__(self, handler, request, options): def __init__(self, handler, request, options):
super().__init__(handler, request, options) super().__init__(handler, request, options)
self.device_id, self.device = self._get_device() self.device_id, self.device = self._get_device()
def getData(self):
return self.device
def store(self): def store(self):
# need to overwrite the existing key in the config since the layering won't capture the changes otherwise # need to overwrite the existing key in the config since the layering won't capture the changes otherwise
config = Config.get() config = Config.get()
@ -68,10 +66,21 @@ class SdrDeviceController(SettingsFormController):
config["sdrs"] = sdrs config["sdrs"] = sdrs
super().store() super().store()
def _get_device(self):
device_id = unquote(self.request.matches.group(1))
if device_id not in Config.get()["sdrs"]:
return None
return device_id, Config.get()["sdrs"][device_id]
class SdrDeviceController(SdrFormController):
def getData(self):
return self.device
def getSections(self): def getSections(self):
try: try:
description = SdrDeviceDescription.getByType(self.device["type"]) description = SdrDeviceDescription.getByType(self.device["type"])
return [description.getSection()] return [description.getDeviceSection()]
except SdrDeviceDescriptionMissing: except SdrDeviceDescriptionMissing:
# TODO provide a generic interface that allows to switch the type # TODO provide a generic interface that allows to switch the type
return [] return []
@ -79,12 +88,6 @@ class SdrDeviceController(SettingsFormController):
def getTitle(self): def getTitle(self):
return self.device["name"] return self.device["name"]
def _get_device(self):
device_id = unquote(self.request.matches.group(1))
if device_id not in Config.get()["sdrs"]:
return None
return device_id, Config.get()["sdrs"][device_id]
def header_variables(self): def header_variables(self):
variables = super().header_variables() variables = super().header_variables()
variables["assets_prefix"] = "../../" variables["assets_prefix"] = "../../"
@ -123,3 +126,47 @@ class SdrDeviceController(SettingsFormController):
self.send_response("device not found", code=404) self.send_response("device not found", code=404)
return return
self.serve_template("settings/general.html", **self.template_variables()) self.serve_template("settings/general.html", **self.template_variables())
class SdrProfileController(SdrFormController):
def __init__(self, handler, request, options):
super().__init__(handler, request, options)
self.profile_id, self.profile = self._get_profile()
def getData(self):
return self.profile
def _get_profile(self):
profile_id = unquote(self.request.matches.group(2))
if self.device_id not in Config.get()["sdrs"]:
return None
if profile_id not in Config.get()["sdrs"][self.device_id]["profiles"]:
return None
return profile_id, Config.get()["sdrs"][self.device_id]["profiles"][profile_id]
def getSections(self):
try:
description = SdrDeviceDescription.getByType(self.device["type"])
return [description.getProfileSection()]
except SdrDeviceDescriptionMissing:
# TODO provide a generic interface that allows to switch the type
return []
def getTitle(self):
return self.profile["name"]
def header_variables(self):
variables = super().header_variables()
variables["assets_prefix"] = "../../../"
return variables
def template_variables(self):
variables = super().template_variables()
variables["assets_prefix"] = "../../../"
return variables
def indexAction(self):
if self.profile is None:
self.send_response("profile not found", code=404)
return
self.serve_template("settings/general.html", **self.template_variables())

View File

@ -313,3 +313,9 @@ class DropdownInput(Input):
class DropdownEnum(Enum): class DropdownEnum(Enum):
def toOption(self): def toOption(self):
return Option(self.name, str(self)) return Option(self.name, str(self))
class ModesInput(DropdownInput):
def __init__(self, id, label):
options = [Option(m.modulation, m.name) for m in Modes.getAvailableModes()]
super().__init__(id, label, options)

View File

@ -6,7 +6,7 @@ from owrx.controllers.api import ApiController
from owrx.controllers.metrics import MetricsController from owrx.controllers.metrics import MetricsController
from owrx.controllers.settings import SettingsController from owrx.controllers.settings import SettingsController
from owrx.controllers.settings.general import GeneralSettingsController from owrx.controllers.settings.general import GeneralSettingsController
from owrx.controllers.settings.sdr import SdrDeviceListController, SdrDeviceController from owrx.controllers.settings.sdr import SdrDeviceListController, SdrDeviceController, SdrProfileController
from owrx.controllers.settings.reporting import ReportingController from owrx.controllers.settings.reporting import ReportingController
from owrx.controllers.settings.backgrounddecoding import BackgroundDecodingController from owrx.controllers.settings.backgrounddecoding import BackgroundDecodingController
from owrx.controllers.settings.decoding import DecodingSettingsController from owrx.controllers.settings.decoding import DecodingSettingsController
@ -117,11 +117,22 @@ class Router(object):
), ),
StaticRoute("/settings/sdr", SdrDeviceListController), StaticRoute("/settings/sdr", SdrDeviceListController),
RegexRoute("^/settings/sdr/([^/]+)$", SdrDeviceController), RegexRoute("^/settings/sdr/([^/]+)$", SdrDeviceController),
RegexRoute("^/settings/sdr/([^/]+)$", SdrDeviceController, method="POST", options={"action": "processFormData"}), RegexRoute(
"^/settings/sdr/([^/]+)$", SdrDeviceController, method="POST", options={"action": "processFormData"}
),
RegexRoute("^/settings/sdr/([^/]+)/([^/]+)$", SdrProfileController),
RegexRoute(
"^/settings/sdr/([^/]+)/([^/]+)$",
SdrProfileController,
method="POST",
options={"action": "processFormData"},
),
StaticRoute("/settings/bookmarks", BookmarksController), StaticRoute("/settings/bookmarks", BookmarksController),
StaticRoute("/settings/bookmarks", BookmarksController, method="POST", options={"action": "new"}), StaticRoute("/settings/bookmarks", BookmarksController, method="POST", options={"action": "new"}),
RegexRoute("^/settings/bookmarks/(.+)$", BookmarksController, method="POST", options={"action": "update"}), RegexRoute("^/settings/bookmarks/(.+)$", BookmarksController, method="POST", options={"action": "update"}),
RegexRoute("^/settings/bookmarks/(.+)$", BookmarksController, method="DELETE", options={"action": "delete"}), RegexRoute(
"^/settings/bookmarks/(.+)$", BookmarksController, method="DELETE", options={"action": "delete"}
),
StaticRoute("/settings/reporting", ReportingController), StaticRoute("/settings/reporting", ReportingController),
StaticRoute( StaticRoute(
"/settings/reporting", ReportingController, method="POST", options={"action": "processFormData"} "/settings/reporting", ReportingController, method="POST", options={"action": "processFormData"}

View File

@ -10,7 +10,7 @@ from abc import ABC, abstractmethod
from owrx.command import CommandMapper from owrx.command import CommandMapper
from owrx.socket import getAvailablePort from owrx.socket import getAvailablePort
from owrx.property import PropertyStack, PropertyLayer from owrx.property import PropertyStack, PropertyLayer
from owrx.form import Input, TextInput, NumberInput, CheckboxInput from owrx.form import Input, TextInput, NumberInput, CheckboxInput, ModesInput
from owrx.form.converter import OptionalConverter from owrx.form.converter import OptionalConverter
from owrx.form.device import GainInput from owrx.form.device import GainInput
from owrx.controllers.settings import Section from owrx.controllers.settings import Section
@ -492,6 +492,11 @@ class SdrDeviceDescription(object):
NumberInput("waterfall_min_level", "Lowest waterfall level", append="dBFS"), NumberInput("waterfall_min_level", "Lowest waterfall level", append="dBFS"),
NumberInput("waterfall_max_level", "Highest waterfall level", append="dBFS"), NumberInput("waterfall_max_level", "Highest waterfall level", append="dBFS"),
# TODO `schedule` # TODO `schedule`
NumberInput("center_freq", "Center frequency", append="Hz"),
NumberInput("samp_rate", "Sample rate", append="S/s"),
NumberInput("start_freq", "Initial frequency", append="Hz"),
ModesInput("start_mod", "Initial modulation"),
NumberInput("initial_squelch_level", "Initial squelch level", append="dBFS"),
] ]
def getMandatoryKeys(self): def getMandatoryKeys(self):
@ -500,5 +505,19 @@ class SdrDeviceDescription(object):
def getOptionalKeys(self): def getOptionalKeys(self):
return ["ppm", "always-on", "services", "rf_gain", "lfo_offset", "waterfall_min_level", "waterfall_max_level"] return ["ppm", "always-on", "services", "rf_gain", "lfo_offset", "waterfall_min_level", "waterfall_max_level"]
def getSection(self): def getProfileMandatoryKeys(self):
return ["center_freq", "samp_rate", "start_freq", "start_mod"]
def getProfileOptionalKeys(self):
return ["initial_squelch_level", "rf_gain", "lfo_offset", "waterfall_min_level", "waterfall_max_level"]
def getDeviceSection(self):
return OptionalSection("Device settings", self.getInputs(), self.getMandatoryKeys(), self.getOptionalKeys()) return OptionalSection("Device settings", self.getInputs(), self.getMandatoryKeys(), self.getOptionalKeys())
def getProfileSection(self):
return OptionalSection(
"Profile settings",
self.getInputs(),
self.getProfileMandatoryKeys(),
self.getProfileOptionalKeys(),
)

View File

@ -34,5 +34,8 @@ class AirspyDeviceDescription(SoapyConnectorDeviceDescription):
def getOptionalKeys(self): def getOptionalKeys(self):
return super().getOptionalKeys() + ["bias_tee", "bitpack"] return super().getOptionalKeys() + ["bias_tee", "bitpack"]
def getProfileOptionalKeys(self):
return super().getProfileOptionalKeys() + ["bias_tee"]
def getGainStages(self): def getGainStages(self):
return ["LNA", "MIX", "VGA"] return ["LNA", "MIX", "VGA"]

View File

@ -92,3 +92,6 @@ class ConnectorDeviceDescription(SdrDeviceDescription):
def getOptionalKeys(self): def getOptionalKeys(self):
return super().getOptionalKeys() + ["rtltcp_compat", "iqswap"] return super().getOptionalKeys() + ["rtltcp_compat", "iqswap"]
def getProfileOptionalKeys(self):
return super().getProfileOptionalKeys() + ["iqswap"]

View File

@ -21,5 +21,8 @@ class HackrfDeviceDescription(SoapyConnectorDeviceDescription):
def getOptionalKeys(self): def getOptionalKeys(self):
return super().getOptionalKeys() + ["bias_tee"] return super().getOptionalKeys() + ["bias_tee"]
def getProfileOptionalKeys(self):
return super().getProfileOptionalKeys() + ["bias_tee"]
def getGainStages(self): def getGainStages(self):
return ["LNA", "AMP", "VGA"] return ["LNA", "AMP", "VGA"]

View File

@ -29,3 +29,6 @@ class RtlSdrDeviceDescription(ConnectorDeviceDescription):
def getOptionalKeys(self): def getOptionalKeys(self):
return super().getOptionalKeys() + ["device", "bias_tee", "direct_sampling"] return super().getOptionalKeys() + ["device", "bias_tee", "direct_sampling"]
def getProfileOptionalKeys(self):
return super().getProfileOptionalKeys() + ["bias_tee", "direct_sampling"]

View File

@ -20,3 +20,6 @@ class RtlSdrSoapyDeviceDescription(SoapyConnectorDeviceDescription):
def getOptionalKeys(self): def getOptionalKeys(self):
return super().getOptionalKeys() + ["bias_tee", "direct_sampling"] return super().getOptionalKeys() + ["bias_tee", "direct_sampling"]
def getProfileOptionalKeys(self):
return super().getProfileOptionalKeys() + ["bias_tee", "direct_sampling"]

View File

@ -56,3 +56,6 @@ class SdrplayDeviceDescription(SoapyConnectorDeviceDescription):
def getOptionalKeys(self): def getOptionalKeys(self):
return super().getOptionalKeys() + ["bias_tee", "rf_notch", "dab_notch", "if_mode"] return super().getOptionalKeys() + ["bias_tee", "rf_notch", "dab_notch", "if_mode"]
def getProfileOptionalKeys(self):
return super().getProfileOptionalKeys() + ["bias_tee", "rf_notch", "dab_notch", "if_mode"]

View File

@ -100,5 +100,8 @@ class SoapyConnectorDeviceDescription(ConnectorDeviceDescription):
def getOptionalKeys(self): def getOptionalKeys(self):
return super().getOptionalKeys() + ["device", "rf_gain", "antenna"] return super().getOptionalKeys() + ["device", "rf_gain", "antenna"]
def getProfileOptionalKeys(self):
return super().getProfileOptionalKeys() + ["antenna"]
def getGainStages(self): def getGainStages(self):
return None return None