diff --git a/htdocs/lib/settings/SchedulerInput.js b/htdocs/lib/settings/SchedulerInput.js
new file mode 100644
index 0000000..86870e3
--- /dev/null
+++ b/htdocs/lib/settings/SchedulerInput.js
@@ -0,0 +1,17 @@
+$.fn.schedulerInput = function() {
+ this.each(function() {
+ var $container = $(this);
+
+ var update = function(value){
+ $container.find('.option').hide();
+ $container.find('.option.' + value).show();
+ }
+
+ var $select = $container.find('select.mode');
+ $select.on('change', function(e) {
+ var value = $(e.target).val();
+ update(value);
+ });
+ update($select.val());
+ });
+}
\ No newline at end of file
diff --git a/htdocs/settings.js b/htdocs/settings.js
index 30aacad..3ac5e53 100644
--- a/htdocs/settings.js
+++ b/htdocs/settings.js
@@ -6,4 +6,5 @@ $(function(){
$('#waterfall_scheme').waterfallDropdown();
$('#rf_gain').gainInput();
$('.optional-section').optionalSection();
+ $('#scheduler').schedulerInput();
});
\ No newline at end of file
diff --git a/owrx/controllers/assets.py b/owrx/controllers/assets.py
index 696d541..1613eec 100644
--- a/owrx/controllers/assets.py
+++ b/owrx/controllers/assets.py
@@ -152,6 +152,7 @@ class CompiledAssetsController(GzipMixin, ModificationAwareController):
"lib/settings/WaterfallDropdown.js",
"lib/settings/GainInput.js",
"lib/settings/OptionalSection.js",
+ "lib/settings/SchedulerInput.js",
"settings.js",
],
}
diff --git a/owrx/form/device.py b/owrx/form/device.py
index 2254cf3..2a940ab 100644
--- a/owrx/form/device.py
+++ b/owrx/form/device.py
@@ -163,3 +163,126 @@ class RemoteInput(TextInput):
super().__init__(
"remote", "Remote IP and Port", infotext="Remote hostname or IP and port to connect to. Format = IP:Port"
)
+
+
+class SchedulerInput(Input):
+ def __init__(self, id, label):
+ super().__init__(id, label)
+ self.profiles = {}
+
+ def render(self, config):
+ if "profiles" in config:
+ self.profiles = config["profiles"]
+ return super().render(config)
+
+ def render_input(self, value):
+ def render_profiles_select(stage):
+ stage_value = ""
+ if value and "schedule" in value and stage in value["schedule"]:
+ stage_value = value["schedule"][stage]
+
+ return """
+
+ """.format(
+ id="{}-{}".format(self.id, stage),
+ classes=self.input_classes(),
+ disabled="disabled" if self.disabled else "",
+ options="".join(
+ """
+
+ """.format(
+ id=p_id,
+ name=p["name"],
+ selected="selected" if stage_value == p_id else "",
+ )
+ for p_id, p in self.profiles.items()
+ ),
+ )
+
+ return """
+
+
+
+ {entries}
+
+
+ {stages}
+
+
+ """.format(
+ id=self.id,
+ classes=self.input_classes(),
+ disabled="disabled" if self.disabled else "",
+ options=self.render_options(value),
+ entries="".join(
+ """
+
+
+ {select}
+
+ """.format(
+ slot=slot,
+ select=render_profiles_select(slot),
+ )
+ for slot, entry in value["schedule"].items()
+ ),
+ stages="".join(
+ """
+
+
+ {select}
+
+ """.format(
+ name=name,
+ select=render_profiles_select(stage),
+ )
+ for stage, name in [("day", "Day"), ("night", "Night"), ("greyline", "Greyline")]
+ ),
+ )
+
+ def _get_mode(self, value):
+ if value is not None and "type" in value:
+ return value["type"]
+ return ""
+
+ def render_options(self, value):
+ options = [
+ ("static", "Static scheduler"),
+ ("daylight", "Daylight scheduler"),
+ ]
+
+ mode = self._get_mode(value)
+
+ return "".join(
+ """
+
+ """.format(
+ value=value, name=name, selected="selected" if mode == value else ""
+ )
+ for value, name in options
+ )
+
+ def parse(self, data):
+ def getStageValue(stage):
+ input_id = "{id}-{stage}".format(id=self.id, stage=stage)
+ if input_id in data:
+ return data[input_id][0]
+ else:
+ return None
+
+ select_id = "{id}-select".format(id=self.id)
+ if select_id in data:
+ if data[select_id][0] == "static":
+ # TODO parse static fields
+ pass
+ elif data[select_id][0] == "daylight":
+ settings_dict = {s: getStageValue(s) for s in ["day", "night", "greyline"]}
+ # filter out empty ones
+ settings_dict = {s: v for s, v in settings_dict.items() if v}
+ return {self.id: {"type": "daylight", "schedule": settings_dict}}
+
+ return {}
diff --git a/owrx/source/__init__.py b/owrx/source/__init__.py
index 2db99b2..d4e2410 100644
--- a/owrx/source/__init__.py
+++ b/owrx/source/__init__.py
@@ -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
+from owrx.form.device import GainInput, SchedulerInput
from owrx.controllers.settings import Section
from typing import List
from enum import Enum, auto
@@ -486,7 +486,7 @@ class SdrDeviceDescription(object):
),
NumberInput("waterfall_min_level", "Lowest waterfall level", append="dBFS"),
NumberInput("waterfall_max_level", "Highest waterfall level", append="dBFS"),
- # TODO `schedule`
+ SchedulerInput("scheduler", "Scheduler"),
NumberInput("center_freq", "Center frequency", append="Hz"),
NumberInput("samp_rate", "Sample rate", append="S/s"),
NumberInput("start_freq", "Initial frequency", append="Hz"),
@@ -502,7 +502,16 @@ class SdrDeviceDescription(object):
return ["name", "enabled"]
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",
+ "scheduler",
+ ]
def getProfileMandatoryKeys(self):
return ["center_freq", "samp_rate", "start_freq", "start_mod"]