combine waterfall_[min|max]_level into a single config

This commit is contained in:
Jakob Ketterl 2021-02-25 15:13:39 +01:00
parent f6f0a87002
commit 5cd9d386a6
9 changed files with 95 additions and 24 deletions

View File

@ -33,7 +33,7 @@ config_webrx: configuration options for OpenWebRX
""" """
# configuration version. please only modify if you're able to perform the associated migration steps. # configuration version. please only modify if you're able to perform the associated migration steps.
version = 4 version = 5
# NOTE: you can find additional information about configuring OpenWebRX in the Wiki: # NOTE: you can find additional information about configuring OpenWebRX in the Wiki:
# https://github.com/jketterl/openwebrx/wiki/Configuration-guide # https://github.com/jketterl/openwebrx/wiki/Configuration-guide
@ -258,13 +258,12 @@ sdrs = {
#waterfall_colors = [0x0000FF, 0x00FF00, 0xFF0000] #waterfall_colors = [0x0000FF, 0x00FF00, 0xFF0000]
### Waterfall calibration ### Waterfall calibration
#waterfall_min_level = -88 # in dB #waterfall_levels = {"min": -88, "max": -20} # in dB
#waterfall_max_level = -20
waterfall_auto_level_margin = {"min": 3, "max": 10, "min_range": 50} waterfall_auto_level_margin = {"min": 3, "max": 10, "min_range": 50}
# Note: When the auto waterfall level button is clicked, the following happens: # Note: When the auto waterfall level button is clicked, the following happens:
# [waterfall_min_level] = [current_min_power_level] - [waterfall_auto_level_margin["min"]] # [waterfall_levels.min] = [current_min_power_level] - [waterfall_auto_level_margin["min"]]
# [waterfall_max_level] = [current_max_power_level] + [waterfall_auto_level_margin["max"]] # [waterfall_levels.max] = [current_max_power_level] + [waterfall_auto_level_margin["max"]]
# #
# ___|________________________________________|____________________________________|________________________________________|___> signal power # ___|________________________________________|____________________________________|________________________________________|___> signal power
# \_waterfall_auto_level_margin["min"]_/ |__ current_min_power_level | \_waterfall_auto_level_margin["max"]_/ # \_waterfall_auto_level_margin["min"]_/ |__ current_min_power_level | \_waterfall_auto_level_margin["max"]_/

View File

@ -717,10 +717,10 @@ function on_ws_recv(evt) {
var config = json['value']; var config = json['value'];
if ('waterfall_colors' in config) if ('waterfall_colors' in config)
waterfall_colors = buildWaterfallColors(config['waterfall_colors']); waterfall_colors = buildWaterfallColors(config['waterfall_colors']);
if ('waterfall_min_level' in config) if ('waterfall_levels' in config) {
waterfall_min_level_default = config['waterfall_min_level']; waterfall_min_level_default = config['waterfall_levels']['min'];
if ('waterfall_max_level' in config) waterfall_max_level_default = config['waterfall_levels']['max'];
waterfall_max_level_default = config['waterfall_max_level']; }
if ('waterfall_auto_level_margin' in config) if ('waterfall_auto_level_margin' in config)
waterfall_auto_level_margin = config['waterfall_auto_level_margin']; waterfall_auto_level_margin = config['waterfall_auto_level_margin'];
waterfallColorsDefault(); waterfallColorsDefault();

View File

@ -2,7 +2,7 @@ from owrx.property import PropertyLayer
defaultConfig = PropertyLayer( defaultConfig = PropertyLayer(
version=4, version=5,
max_clients=20, max_clients=20,
receiver_name="[Callsign]", receiver_name="[Callsign]",
receiver_location="Budapest, Hungary", receiver_location="Budapest, Hungary",
@ -23,8 +23,7 @@ defaultConfig = PropertyLayer(
digital_voice_dmr_id_lookup=True, digital_voice_dmr_id_lookup=True,
# sdrs=... # sdrs=...
waterfall_scheme="GoogleTurboWaterfall", waterfall_scheme="GoogleTurboWaterfall",
waterfall_min_level=-88, waterfall_levels=PropertyLayer(min=-88, max=-20),
waterfall_max_level=-20,
waterfall_auto_level_margin=PropertyLayer(min=3, max=10, min_range=50), waterfall_auto_level_margin=PropertyLayer(min=3, max=10, min_range=50),
frequency_display_precision=4, frequency_display_precision=4,
squelch_auto_margin=10, squelch_auto_margin=10,

View File

@ -59,3 +59,6 @@ class DynamicConfig(PropertyLayer):
def __dict__(self): def __dict__(self):
return {k: v for k, v in super().__dict__().items() if v is not DynamicConfig._deleted} return {k: v for k, v in super().__dict__().items() if v is not DynamicConfig._deleted}
def keys(self):
return [k for k in super().keys() if self.__contains__(k)]

View File

@ -41,7 +41,6 @@ class ConfigMigratorVersion2(ConfigMigrator):
class ConfigMigratorVersion3(ConfigMigrator): class ConfigMigratorVersion3(ConfigMigrator):
def migrate(self, config): def migrate(self, config):
# inline import due to circular dependencies # inline import due to circular dependencies
from owrx.waterfall import WaterfallOptions from owrx.waterfall import WaterfallOptions
@ -61,12 +60,42 @@ class ConfigMigratorVersion3(ConfigMigrator):
config["version"] = 4 config["version"] = 4
class ConfigMigratorVersion4(ConfigMigrator):
def _replaceWaterfallLevels(self, instance):
if (
"waterfall_min_level" in instance
and "waterfall_max_level" in instance
and not "waterfall_levels" in instance
):
instance["waterfall_levels"] = {
"min": instance["waterfall_min_level"],
"max": instance["waterfall_max_level"],
}
del instance["waterfall_min_level"]
del instance["waterfall_max_level"]
def migrate(self, config):
# migrate root level
self._replaceWaterfallLevels(config)
if "sdrs" in config:
for device in config["sdrs"].__dict__().values():
# migrate device level
self._replaceWaterfallLevels(device)
if "profiles" in device:
for profile in device["profiles"].__dict__().values():
# migrate profile level
self._replaceWaterfallLevels(profile)
config["version"] = 5
class Migrator(object): class Migrator(object):
currentVersion = 4 currentVersion = 5
migrators = { migrators = {
1: ConfigMigratorVersion1(), 1: ConfigMigratorVersion1(),
2: ConfigMigratorVersion2(), 2: ConfigMigratorVersion2(),
3: ConfigMigratorVersion3(), 3: ConfigMigratorVersion3(),
4: ConfigMigratorVersion4(),
} }
@staticmethod @staticmethod

View File

@ -113,8 +113,7 @@ class OpenWebRxClient(Client, metaclass=ABCMeta):
class OpenWebRxReceiverClient(OpenWebRxClient, SdrSourceEventClient): class OpenWebRxReceiverClient(OpenWebRxClient, SdrSourceEventClient):
sdr_config_keys = [ sdr_config_keys = [
"waterfall_min_level", "waterfall_levels",
"waterfall_max_level",
"samp_rate", "samp_rate",
"start_mod", "start_mod",
"start_freq", "start_freq",

View File

@ -12,6 +12,7 @@ from owrx.form import (
from owrx.form.converter import WaterfallColorsConverter from owrx.form.converter import WaterfallColorsConverter
from owrx.form.receiverid import ReceiverKeysConverter from owrx.form.receiverid import ReceiverKeysConverter
from owrx.form.gfx import AvatarInput, TopPhotoInput from owrx.form.gfx import AvatarInput, TopPhotoInput
from owrx.form.device import WaterfallLevelsInput
from owrx.waterfall import WaterfallOptions from owrx.waterfall import WaterfallOptions
import shutil import shutil
import os import os
@ -102,8 +103,7 @@ class GeneralSettingsController(SettingsFormController):
infotext="If fft_voverlap_factor is above 0, multiple FFTs will be used for creating a line on the " infotext="If fft_voverlap_factor is above 0, multiple FFTs will be used for creating a line on the "
+ "diagram.", + "diagram.",
), ),
NumberInput("waterfall_min_level", "Lowest waterfall level", append="dBFS"), WaterfallLevelsInput("waterfall_levels", "Waterfall levels"),
NumberInput("waterfall_max_level", "Highest waterfall level", append="dBFS"),
), ),
Section( Section(
"Compression", "Compression",

View File

@ -338,3 +338,47 @@ class SchedulerInput(Input):
return {self.id: {"type": "daylight", "schedule": settings_dict}} return {self.id: {"type": "daylight", "schedule": settings_dict}}
return {} return {}
class WaterfallLevelsInput(Input):
def render_input(self, value):
return """
<div class="row" id="{id}">
{inputs}
</div>
""".format(
id=self.id,
inputs="".join(
"""
<div class="col row">
<label class="col-3 col-form-label col-form-label-sm" for="{id}-{name}">{label}</label>
<div class="col-9 input-group input-group-sm">
<input type="number" class="{classes}" name="{id}-{name}" value="{value}" {disabled}>
<div class="input-group-append">
<span class="input-group-text">dBFS</span>
</div>
</div>
</div>
""".format(
id=self.id,
name=name,
label=label,
value=value[name] if value and name in value else "0",
classes=self.input_classes(),
disabled="disabled" if self.disabled else "",
)
for name, label in [("min", "Minimum"), ("max", "Maximum")]
)
)
def parse(self, data):
def getValue(name):
key = "{}-{}".format(self.id, name)
if key in data:
return {name: data[key][0]}
raise KeyError("waterfall key not found")
try:
return {self.id: {k: v for name in ["min", "max"] for k, v in getValue(name).items()}}
except KeyError:
return {}

View File

@ -13,7 +13,7 @@ from owrx.property import PropertyStack, PropertyLayer, PropertyFilter
from owrx.property.filter import ByLambda from owrx.property.filter import ByLambda
from owrx.form import Input, TextInput, NumberInput, CheckboxInput, ModesInput 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, SchedulerInput from owrx.form.device import GainInput, SchedulerInput, WaterfallLevelsInput
from owrx.controllers.settings import Section from owrx.controllers.settings import Section
from typing import List from typing import List
from enum import Enum, auto from enum import Enum, auto
@ -492,8 +492,7 @@ class SdrDeviceDescription(object):
infotext="Use this when the actual receiving frequency differs from the frequency to be tuned on the" infotext="Use this when the actual receiving frequency differs from the frequency to be tuned on the"
+ " device. <br/> Formula: Center frequency + oscillator offset = sdr tune frequency", + " device. <br/> Formula: Center frequency + oscillator offset = sdr tune frequency",
), ),
NumberInput("waterfall_min_level", "Lowest waterfall level", append="dBFS"), WaterfallLevelsInput("waterfall_levels", "Waterfall levels"),
NumberInput("waterfall_max_level", "Highest waterfall level", append="dBFS"),
SchedulerInput("scheduler", "Scheduler"), SchedulerInput("scheduler", "Scheduler"),
NumberInput("center_freq", "Center frequency", append="Hz"), NumberInput("center_freq", "Center frequency", append="Hz"),
NumberInput("samp_rate", "Sample rate", append="S/s"), NumberInput("samp_rate", "Sample rate", append="S/s"),
@ -516,8 +515,7 @@ class SdrDeviceDescription(object):
"services", "services",
"rf_gain", "rf_gain",
"lfo_offset", "lfo_offset",
"waterfall_min_level", "waterfall_levels",
"waterfall_max_level",
"scheduler", "scheduler",
] ]
@ -525,7 +523,7 @@ class SdrDeviceDescription(object):
return ["center_freq", "samp_rate", "start_freq", "start_mod"] return ["center_freq", "samp_rate", "start_freq", "start_mod"]
def getProfileOptionalKeys(self): def getProfileOptionalKeys(self):
return ["initial_squelch_level", "rf_gain", "lfo_offset", "waterfall_min_level", "waterfall_max_level"] return ["initial_squelch_level", "rf_gain", "lfo_offset", "waterfall_levels"]
def getDeviceSection(self): def getDeviceSection(self):
return OptionalSection("Device settings", self.getInputs(), self.getMandatoryKeys(), self.getOptionalKeys()) return OptionalSection("Device settings", self.getInputs(), self.getMandatoryKeys(), self.getOptionalKeys())