implement profile editing page
This commit is contained in:
parent
ed258cc9a0
commit
c5df6a1527
@ -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())
|
||||||
|
@ -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)
|
||||||
|
17
owrx/http.py
17
owrx/http.py
@ -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"}
|
||||||
|
@ -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(),
|
||||||
|
)
|
||||||
|
@ -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"]
|
||||||
|
@ -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"]
|
||||||
|
@ -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"]
|
||||||
|
@ -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"]
|
||||||
|
@ -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"]
|
||||||
|
@ -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"]
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user