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.
version = 4
version = 5
# NOTE: you can find additional information about configuring OpenWebRX in the Wiki:
# https://github.com/jketterl/openwebrx/wiki/Configuration-guide
@ -258,13 +258,12 @@ sdrs = {
#waterfall_colors = [0x0000FF, 0x00FF00, 0xFF0000]
### Waterfall calibration
#waterfall_min_level = -88 # in dB
#waterfall_max_level = -20
#waterfall_levels = {"min": -88, "max": -20} # in dB
waterfall_auto_level_margin = {"min": 3, "max": 10, "min_range": 50}
# 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_max_level] = [current_max_power_level] + [waterfall_auto_level_margin["max"]]
# [waterfall_levels.min] = [current_min_power_level] - [waterfall_auto_level_margin["min"]]
# [waterfall_levels.max] = [current_max_power_level] + [waterfall_auto_level_margin["max"]]
#
# ___|________________________________________|____________________________________|________________________________________|___> signal power
# \_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'];
if ('waterfall_colors' in config)
waterfall_colors = buildWaterfallColors(config['waterfall_colors']);
if ('waterfall_min_level' in config)
waterfall_min_level_default = config['waterfall_min_level'];
if ('waterfall_max_level' in config)
waterfall_max_level_default = config['waterfall_max_level'];
if ('waterfall_levels' in config) {
waterfall_min_level_default = config['waterfall_levels']['min'];
waterfall_max_level_default = config['waterfall_levels']['max'];
}
if ('waterfall_auto_level_margin' in config)
waterfall_auto_level_margin = config['waterfall_auto_level_margin'];
waterfallColorsDefault();

View File

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

View File

@ -59,3 +59,6 @@ class DynamicConfig(PropertyLayer):
def __dict__(self):
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):
def migrate(self, config):
# inline import due to circular dependencies
from owrx.waterfall import WaterfallOptions
@ -61,12 +60,42 @@ class ConfigMigratorVersion3(ConfigMigrator):
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):
currentVersion = 4
currentVersion = 5
migrators = {
1: ConfigMigratorVersion1(),
2: ConfigMigratorVersion2(),
3: ConfigMigratorVersion3(),
4: ConfigMigratorVersion4(),
}
@staticmethod

View File

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

View File

@ -12,6 +12,7 @@ from owrx.form import (
from owrx.form.converter import WaterfallColorsConverter
from owrx.form.receiverid import ReceiverKeysConverter
from owrx.form.gfx import AvatarInput, TopPhotoInput
from owrx.form.device import WaterfallLevelsInput
from owrx.waterfall import WaterfallOptions
import shutil
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 "
+ "diagram.",
),
NumberInput("waterfall_min_level", "Lowest waterfall level", append="dBFS"),
NumberInput("waterfall_max_level", "Highest waterfall level", append="dBFS"),
WaterfallLevelsInput("waterfall_levels", "Waterfall levels"),
),
Section(
"Compression",

View File

@ -338,3 +338,47 @@ class SchedulerInput(Input):
return {self.id: {"type": "daylight", "schedule": settings_dict}}
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.form import Input, TextInput, NumberInput, CheckboxInput, ModesInput
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 typing import List
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"
+ " device. <br/> Formula: Center frequency + oscillator offset = sdr tune frequency",
),
NumberInput("waterfall_min_level", "Lowest waterfall level", append="dBFS"),
NumberInput("waterfall_max_level", "Highest waterfall level", append="dBFS"),
WaterfallLevelsInput("waterfall_levels", "Waterfall levels"),
SchedulerInput("scheduler", "Scheduler"),
NumberInput("center_freq", "Center frequency", append="Hz"),
NumberInput("samp_rate", "Sample rate", append="S/s"),
@ -516,8 +515,7 @@ class SdrDeviceDescription(object):
"services",
"rf_gain",
"lfo_offset",
"waterfall_min_level",
"waterfall_max_level",
"waterfall_levels",
"scheduler",
]
@ -525,7 +523,7 @@ class SdrDeviceDescription(object):
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"]
return ["initial_squelch_level", "rf_gain", "lfo_offset", "waterfall_levels"]
def getDeviceSection(self):
return OptionalSection("Device settings", self.getInputs(), self.getMandatoryKeys(), self.getOptionalKeys())