diff --git a/code/espurna/relay.cpp b/code/espurna/relay.cpp index 0db68037..5912d695 100644 --- a/code/espurna/relay.cpp +++ b/code/espurna/relay.cpp @@ -1041,7 +1041,7 @@ void relayToggle(unsigned char id) { #endif } -unsigned char relayCount() { +size_t relayCount() { return _relays.size(); } @@ -1217,6 +1217,24 @@ void _relayWebSocketUpdate(JsonObject& root) { } } +void _relayWebSocketRelayConfig(JsonArray& relay, size_t id) { + relay.add(static_cast(getSetting({"relayProv", id}, _relayProvider(id)))); + relay.add(getSetting({"relayName", id})); + relay.add(getSetting({"relayBoot", id}, _relayBootMode(id))); + +#if MQTT_SUPPORT + relay.add(getSetting({"relayTopicSub", id}, _relayMqttTopicSub(id))); + relay.add(getSetting({"relayTopicPub", id}, _relayMqttTopicPub(id))); + relay.add(static_cast(getSetting({"relayTopicMode", id}, + _relayMqttTopicMode(id)))); + relay.add(static_cast(getSetting({"relayMqttDisc", id}, + _relayMqttDisconnectionStatus(id)))); +#endif + + relay.add(static_cast(_relays[id].pulse)); + relay.add(_relays[id].pulse_ms / 1000.0); +} + void _relayWebSocketSendRelays(JsonObject& root) { if (!relayCount()) { return; @@ -1228,21 +1246,18 @@ void _relayWebSocketSendRelays(JsonObject& root) { config["start"] = 0; { - const char* schema_keys[] = { - "prov", - "name", - "boot", -#if SCHEDULER_SUPPORT - "sch_last", -#endif + static constexpr const char* const schema_keys[] PROGMEM = { + "relayProv", + "relayName", + "relayBoot", #if MQTT_SUPPORT - "topic_pub", - "topic_sub", - "topic_mode", - "mqtt_disc", + "relayTopicPub", + "relayTopicSub", + "relayTopicMode", + "relayMqttDisc", #endif - "pulse", - "pulse_time" + "relayPulse", + "relayTime" }; JsonArray& schema = config.createNestedArray("schema"); @@ -1250,29 +1265,14 @@ void _relayWebSocketSendRelays(JsonObject& root) { } { - JsonArray& relays = config.createNestedArray("relays"); - - for (unsigned char id = 0; id < relayCount(); ++id) { - JsonArray& relay = relays.createNestedArray(); - relay.add(_relays[id].provider->id()); - relay.add(getSetting({"relayName", id})); - relay.add(getSetting({"relayBoot", id}, _relayBootMode(id))); - -#if SCHEDULER_SUPPORT - relay.add(getSetting({"relayLastSch", id}, SCHEDULER_RESTORE_LAST_SCHEDULE)); -#endif + JsonArray& cfg = config.createNestedArray("cfg"); + JsonArray& desc = config.createNestedArray("desc"); -#if MQTT_SUPPORT - relay.add(getSetting({"relayTopicSub", id}, _relayMqttTopicSub(id))); - relay.add(getSetting({"relayTopicPub", id}, _relayMqttTopicPub(id))); - relay.add(static_cast(getSetting({"relayTopicMode", id}, - _relayMqttTopicMode(id)))); - relay.add(static_cast(getSetting({"relayMqttDisc", id}, - _relayMqttDisconnectionStatus(id)))); -#endif + for (size_t id = 0; id < relayCount(); ++id) { + desc.add(_relays[id].provider->id()); - relay.add(static_cast(_relays[id].pulse)); - relay.add(_relays[id].pulse_ms / 1000.0); + JsonArray& relay = cfg.createNestedArray(); + _relayWebSocketRelayConfig(relay, id); } } } diff --git a/code/espurna/relay.h b/code/espurna/relay.h index 2847435e..d368f111 100644 --- a/code/espurna/relay.h +++ b/code/espurna/relay.h @@ -82,7 +82,7 @@ bool relayStatusTarget(unsigned char id); void relayToggle(unsigned char id, bool report, bool group_report); void relayToggle(unsigned char id); -unsigned char relayCount(); +size_t relayCount(); const String& relayPayloadOn(); const String& relayPayloadOff(); diff --git a/code/espurna/scheduler.cpp b/code/espurna/scheduler.cpp index b5cf266f..bae3726f 100644 --- a/code/espurna/scheduler.cpp +++ b/code/espurna/scheduler.cpp @@ -21,16 +21,44 @@ Adapted by Xose PĂ©rez constexpr int SchedulerDummySwitchId { 0xff }; -int _sch_restore = 0; +#if RELAY_SUPPORT + +size_t schedulableCount() { + return relayCount(); +} + +#elif CURTAIN_SUPPORT + +size_t schedulableCount() { + return curtainCount() +} -unsigned char schedulableCount() { - return relayCount() -#ifdef CURTAIN_SUPPORT - + curtainCount() #endif - ; + +// ----------------------------------------------------------------------------- + +namespace scheduler { +namespace build { + +constexpr size_t max() { + return SCHEDULER_MAX_SCHEDULES; +} + +constexpr int defaultType() { + return SCHEDULER_TYPE_SWITCH; +} + +constexpr const char* const weekdays() { + return SCHEDULER_WEEKDAYS; } +constexpr bool restoreLast() { + return 1 == SCHEDULER_RESTORE_LAST_SCHEDULE; +} + +} // namespace build +} // namespace scheduler + // ----------------------------------------------------------------------------- #if WEB_SUPPORT @@ -48,37 +76,55 @@ void _schWebSocketOnConnected(JsonObject &root){ if (!schedulableCount()) return; - JsonObject &schedules = root.createNestedObject("schedules"); - schedules["max"] = SCHEDULER_MAX_SCHEDULES; - - JsonArray& enabled = schedules.createNestedArray("schEnabled"); - JsonArray& switch_ = schedules.createNestedArray("schSwitch"); - JsonArray& action = schedules.createNestedArray("schAction"); - JsonArray& type = schedules.createNestedArray("schType"); - JsonArray& hour = schedules.createNestedArray("schHour"); - JsonArray& minute = schedules.createNestedArray("schMinute"); - JsonArray& utc = schedules.createNestedArray("schUTC"); - JsonArray& weekdays = schedules.createNestedArray("schWDs"); + JsonObject& config = root.createNestedObject("schConfig"); + config["max"] = scheduler::build::max(); + + { + static constexpr const char* const schema_keys[] PROGMEM = { + "schEnabled", + "schRestore", + "schType", + "schSwitch", + "schAction", + "schHour", + "schMinute", + "schUTC", + "schWDs" + }; + + JsonArray& schema = config.createNestedArray("schema"); + schema.copyFrom(schema_keys, sizeof(schema_keys) / sizeof(*schema_keys)); + } uint8_t size = 0; - for (unsigned char i = 0; i < SCHEDULER_MAX_SCHEDULES; i++) { - if (!getSetting({"schSwitch", i}).length()) break; + JsonArray& schedules = config.createNestedArray("schedules"); + + for (size_t id = 0; id < scheduler::build::max(); ++id) { + auto schedulerSwitch = getSetting({"schSwitch", id}); + if (!schedulerSwitch.length()) { + break; + } + + JsonArray& entry = schedules.createNestedArray(); ++size; - enabled.add(getSetting({"schEnabled", i}, false) ? 1 : 0); - utc.add(getSetting({"schUTC", i}, 0)); + entry.add(getSetting({"schEnabled", id}, false) ? 1 : 0); + entry.add(getSetting({"schRestore", id}, scheduler::build::restoreLast()) ? 1 : 0); + + entry.add(getSetting({"schType", id}, scheduler::build::defaultType())); + entry.add(schedulerSwitch); + entry.add(getSetting({"schAction", id}, 0)); - switch_.add(getSetting({"schSwitch", i}, 0)); - action.add(getSetting({"schAction", i}, 0)); - type.add(getSetting({"schType", i}, SCHEDULER_TYPE_SWITCH)); - hour.add(getSetting({"schHour", i}, 0)); - minute.add(getSetting({"schMinute", i}, 0)); - weekdays.add(getSetting({"schWDs", i}, SCHEDULER_WEEKDAYS)); + entry.add(getSetting({"schHour", id}, 0)); + entry.add(getSetting({"schMinute", id}, 0)); + + entry.add(getSetting({"schWDs", id}, scheduler::build::weekdays())); + entry.add(getSetting({"schUTC", id}, 0)); } - schedules["size"] = size; - schedules["start"] = 0; + config["size"] = size; + config["start"] = 0; } @@ -87,17 +133,11 @@ void _schWebSocketOnConnected(JsonObject &root){ // ----------------------------------------------------------------------------- void _schConfigure() { - - bool delete_flag = false; - - for (unsigned char i = 0; i < SCHEDULER_MAX_SCHEDULES; i++) { - + for (unsigned char i = 0; i < scheduler::build::max(); i++) { int sch_switch = getSetting({"schSwitch", i}, SchedulerDummySwitchId); - if (sch_switch == SchedulerDummySwitchId) delete_flag = true; - - if (delete_flag) { - + if (sch_switch == SchedulerDummySwitchId) { delSetting({"schEnabled", i}); + delSetting({"schRestore", i}); delSetting({"schSwitch", i}); delSetting({"schAction", i}); delSetting({"schHour", i}); @@ -105,38 +145,31 @@ void _schConfigure() { delSetting({"schWDs", i}); delSetting({"schType", i}); delSetting({"schUTC", i}); - } else { - - #if DEBUG_SUPPORT - - bool sch_enabled = getSetting({"schEnabled", i}, false); - int sch_action = getSetting({"schAction", i}, 0); - int sch_hour = getSetting({"schHour", i}, 0); - int sch_minute = getSetting({"schMinute", i}, 0); - bool sch_utc = getSetting({"schUTC", i}, false); - String sch_weekdays = getSetting({"schWDs", i}, SCHEDULER_WEEKDAYS); - - int type = getSetting({"schType", i}, SCHEDULER_TYPE_SWITCH); - const auto sch_type = - (SCHEDULER_TYPE_SWITCH == type) ? "switch" : - (SCHEDULER_TYPE_CURTAIN == type) ? "curtain" : - (SCHEDULER_TYPE_DIM == type) ? "channel" : "unknown"; - - DEBUG_MSG_P( - PSTR("[SCH] Schedule #%d: %s #%d to %d at %02d:%02d %s on %s%s\n"), - i, sch_type, sch_switch, - sch_action, sch_hour, sch_minute, sch_utc ? "UTC" : "local time", - sch_weekdays.c_str(), - sch_enabled ? "" : " (disabled)" - ); - - #endif // DEBUG_SUPPORT - +#if DEBUG_SUPPORT + bool sch_enabled = getSetting({"schEnabled", i}, false); + int sch_action = getSetting({"schAction", i}, 0); + int sch_hour = getSetting({"schHour", i}, 0); + int sch_minute = getSetting({"schMinute", i}, 0); + bool sch_utc = getSetting({"schUTC", i}, false); + String sch_weekdays = getSetting({"schWDs", i}, SCHEDULER_WEEKDAYS); + + int type = getSetting({"schType", i}, SCHEDULER_TYPE_SWITCH); + const auto sch_type = + (SCHEDULER_TYPE_SWITCH == type) ? "switch" : + (SCHEDULER_TYPE_CURTAIN == type) ? "curtain" : + (SCHEDULER_TYPE_DIM == type) ? "channel" : "unknown"; + + DEBUG_MSG_P( + PSTR("[SCH] Schedule #%d: %s #%d to %d at %02d:%02d %s on %s%s\n"), + i, sch_type, sch_switch, + sch_action, sch_hour, sch_minute, sch_utc ? "UTC" : "local time", + sch_weekdays.c_str(), + sch_enabled ? "" : " (disabled)" + ); +#endif // DEBUG_SUPPORT } - } - } bool _schIsThisWeekday(int day, const String& weekdays){ @@ -169,22 +202,17 @@ void _schAction(unsigned char sch_id, int sch_action, int sch_switch) { } else { relayStatus(sch_switch, sch_action); } +#if LIGHT_PROVIDER != LIGHT_PROVIDER_NONE + } else if (SCHEDULER_TYPE_DIM == sch_type) { + DEBUG_MSG_P(PSTR("[SCH] Set channel %d value to %d\n"), sch_switch, sch_action); + lightChannel(sch_switch, sch_action); + lightUpdate(); +#elif CURTAIN_SUPPORT + } else if (SCHEDULER_TYPE_CURTAIN == sch_type) { + DEBUG_MSG_P(PSTR("[SCH] Set curtain %d value to %d\n"), sch_switch, sch_action); + curtainSetPosition(sch_switch, sch_action); +#endif } - - #if LIGHT_PROVIDER != LIGHT_PROVIDER_NONE - if (SCHEDULER_TYPE_DIM == sch_type) { - DEBUG_MSG_P(PSTR("[SCH] Set channel %d value to %d\n"), sch_switch, sch_action); - lightChannel(sch_switch, sch_action); - lightUpdate(); - } - #endif - - #if CURTAIN_SUPPORT == 1 - if (SCHEDULER_TYPE_CURTAIN == sch_type) { - DEBUG_MSG_P(PSTR("[SCH] Set curtain %d value to %d\n"), sch_switch, sch_action); - curtainSetPosition(sch_switch, sch_action); - } - #endif } #if NTP_LEGACY_SUPPORT @@ -230,9 +258,9 @@ NtpCalendarWeekday _schGetWeekday(time_t timestamp, int daybefore) { #endif -// If daybefore and relay is -1, check with current timestamp -// Otherwise, modify it by moving 'daybefore' days back and only use the 'relay' id -void _schCheck(int relay, int daybefore) { +// If daybefore and target is -1, check with current timestamp +// Otherwise, modify it by moving 'daybefore' days back and only use the 'target' id +void _schCheck(int target, int daybefore) { time_t timestamp = now(); auto calendar_weekday = _schGetWeekday(timestamp, daybefore); @@ -241,7 +269,7 @@ void _schCheck(int relay, int daybefore) { int saved_sch = -1; // Check schedules - for (unsigned char i = 0; i < SCHEDULER_MAX_SCHEDULES; i++) { + for (unsigned char i = 0; i < scheduler::build::max(); i++) { int sch_switch = getSetting({"schSwitch", i}, SchedulerDummySwitchId); if (sch_switch == SchedulerDummySwitchId) break; @@ -266,14 +294,14 @@ void _schCheck(int relay, int daybefore) { sch_hour, sch_minute ); - if (sch_type == SCHEDULER_TYPE_SWITCH && sch_switch == relay && sch_action != 2 && minutes_to_trigger < 0 && minutes_to_trigger > minimum_restore_time) { + if (sch_type == SCHEDULER_TYPE_SWITCH && sch_switch == target && sch_action != 2 && minutes_to_trigger < 0 && minutes_to_trigger > minimum_restore_time) { minimum_restore_time = minutes_to_trigger; saved_action = sch_action; saved_sch = i; } #if LIGHT_PROVIDER != LIGHT_PROVIDER_NONE - if (SCHEDULER_TYPE_DIM == sch_type && sch_switch == relay && minutes_to_trigger < 0 && minutes_to_trigger > minimum_restore_time) { + if (SCHEDULER_TYPE_DIM == sch_type && sch_switch == target && minutes_to_trigger < 0 && minutes_to_trigger > minimum_restore_time) { minimum_restore_time = minutes_to_trigger; saved_action = sch_action; saved_sch = i; @@ -281,31 +309,29 @@ void _schCheck(int relay, int daybefore) { #endif #if CURTAIN_SUPPORT == 1 - if (SCHEDULER_TYPE_CURTAIN == sch_type && sch_switch == relay && minutes_to_trigger < 0 && minutes_to_trigger > minimum_restore_time) { + if (SCHEDULER_TYPE_CURTAIN == sch_type && sch_switch == target && minutes_to_trigger < 0 && minutes_to_trigger > minimum_restore_time) { minimum_restore_time = minutes_to_trigger; saved_action = sch_action; saved_sch = i; } #endif - - - if (minutes_to_trigger == 0 && relay == -1) { + if (minutes_to_trigger == 0 && target == -1) { _schAction(i, sch_action, sch_switch); - DEBUG_MSG_P(PSTR("[SCH] Schedule #%d TRIGGERED!!\n"), i); + DEBUG_MSG_P(PSTR("[SCH] Schedule #%u TRIGGERED!!\n"), i); // Show minutes to trigger every 15 minutes // or every minute if less than 15 minutes to scheduled time. // This only works for schedules on this same day. // For instance, if your scheduler is set for 00:01 you will only // get one notification before the trigger (at 00:00) - } else if (minutes_to_trigger > 0 && relay == -1) { + } else if (minutes_to_trigger > 0 && target == -1) { #if DEBUG_SUPPORT if ((minutes_to_trigger % 15 == 0) || (minutes_to_trigger < 15)) { DEBUG_MSG_P( - PSTR("[SCH] %d minutes to trigger schedule #%d\n"), + PSTR("[SCH] %d minutes to trigger schedule #%u\n"), minutes_to_trigger, i ); } @@ -318,12 +344,12 @@ void _schCheck(int relay, int daybefore) { } if (daybefore >= 0 && daybefore < 7 && minimum_restore_time == -(60 * 24) && saved_action == -1) { - _schCheck(relay, ++daybefore); + _schCheck(target, ++daybefore); return; } if (minimum_restore_time != -(60 * 24) && saved_action != -1 && saved_sch != -1) { - _schAction(saved_sch, saved_action, relay); + _schAction(saved_sch, saved_action, target); } } @@ -348,8 +374,9 @@ void schSetup() { } if (restore_once) { - for (unsigned char i = 0; i < schedulableCount(); i++) { - if (getSetting({"relayLastSch", i}, 1 == SCHEDULER_RESTORE_LAST_SCHEDULE)) { + auto targets = schedulableCount(); + for (unsigned char i = 0; i < targets; i++) { + if (getSetting({"schRestore", i}, scheduler::build::restoreLast())) { _schCheck(i, 0); } } diff --git a/code/html/custom.js b/code/html/custom.js index 216e704a..5e075fa4 100644 --- a/code/html/custom.js +++ b/code/html/custom.js @@ -306,7 +306,7 @@ function getData(form, changed, cleanup) { // Hack: clean-up leftover arrays. // When empty, the receiving side will prune all keys greater than the current one. if (cleanup) { - $(".group-settings").each(function() { + $(".settings-group").each(function() { var haschanged = ("true" === $(this).attr("hasChanged")); if (haschanged && !this.children.length) { var targets = this.dataset.settingsTarget; @@ -448,6 +448,37 @@ function initSelectGPIO(select) { } } +function fillTemplateLineFromCfg(line, id, cfg) { + for (var [key, value] of Object.entries(cfg)) { + var span = $(`span.${key}`, line); + if (span.length) { + span.html(cfg[key]); + continue; + } + + var input = $(`input[name='${key}']`, line); + if (input.length) { + if (input.is("[type='checkbox']")) { + var realId = key + id; + input.prop("checked", cfg[key]) + .attr("id", realId) + .attr("name", realId) + .next().attr("for", realId); + } else { + input.val(cfg[key]); + } + continue; + } + + var select = $(`select[name='${key}']`, line); + if (select.length) { + select.prop("value", cfg[key]); + continue; + } + } + + setOriginalsFromValues($("input,select", line)); +} // ----------------------------------------------------------------------------- // Actions @@ -484,7 +515,7 @@ function setOriginalsFromValues(elems) { function resetOriginals() { setOriginalsFromValues(); - $(".group-settings").attr("haschanged", "false") + $(".settings-group").attr("haschanged", "false") numReboot = numReconnect = numReload = 0; configurationSaved = false; } @@ -1011,53 +1042,49 @@ function moreSchedule() { $("div.more", parent).toggle(); } -function addSchedule(values) { +function addSchedule(cfg, payload) { - var schedules = numSchedules(); - if (schedules >= maxSchedules()) { + var id = numSchedules(); + if (id >= maxSchedules()) { alert("Max number of schedules reached"); return null; } - if (values === undefined) { - values = {}; + if (cfg === undefined) { + return null; + } + + if (payload === undefined) { + payload = {}; } var line = loadConfigTemplate("scheduleTemplate"); var type = "none"; - switch(values.schType) { - case 1: - type = "switch"; - break; - case 2: - type = "light"; - break; - case 3: - type = "curtain"; - break; + switch(cfg.schType) { + case 1: + type = "switch"; + break; + case 2: + type = "light"; + break; + case 3: + type = "curtain"; + break; } - var actions = $("#" + type + "ActionTemplate").children(); - $(line).find("#schActionDiv").append(actions.clone()); - - $(line).find(".button-del-schedule").on("click", delSchedule); - $(line).find(".button-more-schedule").on("click", moreSchedule); + $("#schActionDiv", line) + .append(loadConfigTemplate(type + "ActionTemplate")); - var schUTC_id = "schUTC" + schedules; - $(line).find("input[name='schUTC']").prop("id", schUTC_id).next().prop("for", schUTC_id); + $(".button-del-schedule", line) + .on("click", delSchedule); + $(".button-more-schedule", line) + .on("click", moreSchedule); - var schEnabled_id = "schEnabled" + schedules; - $(line).find("input[name='schEnabled']").prop("id", schEnabled_id).next().prop("for", schEnabled_id); + $("input[type='checkbox']", line) + .prop("checked", false); - $(line).find("input[type='checkbox']").prop("checked", false); - - Object.entries(values).forEach(function(kv) { - var key = kv[0], value = kv[1]; - $("input[name='" + key + "']", line).val(value); - $("select[name='" + key + "']", line).prop("value", value); - $("input[type='checkbox'][name='" + key + "']", line).prop("checked", value); - }); + fillTemplateLineFromCfg(line, id, cfg); line.appendTo("#schedules"); return line; @@ -1068,55 +1095,34 @@ function addSchedule(values) { // Relays // ----------------------------------------------------------------------------- -function initRelayFromSchema(id, relay, schema) { - var result = fromSchema(relay, schema) - if (!result.name.length) { - result.name = "Switch #" + id; - } - - return result; -} - -function initRelays(data) { - - var current = $("#relays > div").length; - if (current > 0) { return; } - - var schema = data.schema; - - data["relays"].forEach(function(relay, id) { - var _relay = initRelayFromSchema(id, relay, schema); - - var line = loadConfigTemplate("relayTemplate"); - - $("span.relay-name", line) - .text(_relay.name) - .attr("data-id", id); - - $("input[type='checkbox']", line) - .prop('checked', false) - .prop('disabled', true) - .attr("data-id", id) - .prop("id", "relay" + id) - .on("change", function (event) { - var target= parseInt($(event.target).attr("data-id"), 10); - var status = $(event.target).prop("checked"); - doToggle(target, status); - }); - - $("label.toggle", line) - .prop("for", "relay" + id); - - line.appendTo("#relays"); +function initRelay(id, cfg, payload) { + var line = loadConfigTemplate("relayTemplate"); + $("span.relayName", line) + .text(cfg.relayName) + .attr("data-id", id) + .attr("title", payload["desc"][id]); + + $("input[type='checkbox']", line) + .prop('checked', false) + .prop('disabled', true) + .attr("data-id", id) + .prop("id", "relay" + id) + .on("change", function (event) { + var target= parseInt($(event.target).attr("data-id"), 10); + var status = $(event.target).prop("checked"); + doToggle(target, status); + }); - }); + $("label.toggle", line) + .prop("for", "relay" + id); + line.appendTo("#relays"); } function updateRelays(data) { var size = data.size; for (var i=0; i legend").length; // there is a legend per relay - if (current > 0) { return; } - - var schema = data.schema; - - data["relays"].forEach(function(relay, id) { - var _relay = initRelayFromSchema(id, relay, schema); - var line = loadConfigTemplate("relayConfigTemplate"); - - $("span.name", line).html(_relay.name); - $("span.prov", line).html(_relay.prov); - $("select[name='relayBoot']", line).val(_relay.boot); - $("select[name='relayPulse']", line).val(_relay.pulse); - $("input[name='relayTime']", line).val(_relay.pulse_time); - - if (schema.includes("sch_last")) { - $("input[name='relayLastSch']", line) - .prop("checked", _relay.sch_last) - .attr("id", "relayLastSch" + id) - .attr("name", "relayLastSch" + id) - .next().attr("for","relayLastSch" + (id)); - } - - if (schema.includes("group")) { - $("input[name='mqttGroup']", line).val(_relay.group); - } - if (schema.includes("group_sync")) { - $("select[name='mqttGroupSync']", line).val(_relay.group_sync); - } - if (schema.includes("on_disc")) { - $("select[name='relayOnDisc']", line).val(_relay.on_disc); - } - - setOriginalsFromValues($("input,select", line)); - line.appendTo("#relayConfig"); - - // Populate the relay SELECTs on the configuration panel - $("select.isrelay").append( - $("") - .attr("value", id) - .text(name) - ); +function initRelayConfig(id, cfg, payload) { + var line = loadConfigTemplate("relayConfigTemplate"); + fillTemplateLineFromCfg(line, id, cfg); - ++id; - }); + line.appendTo("#relayConfig"); + // Populate the relay SELECTs on the configuration panel + $("select.isrelay").append( + $("") + .attr("value", id) + .text(name) + ); } // ----------------------------------------------------------------------------- @@ -1886,18 +1856,16 @@ function processData(data) { // Relays scheduler // ----------------------------------------------------------------------------- - if ("schedules" === key) { - $("#schedules").attr("data-settings-max", value.max); - for (var i=0; i { + let cfg = fromSchema(entries, id); + addSchedule(cfg, value); + }); + return; } @@ -1906,8 +1874,25 @@ function processData(data) { // --------------------------------------------------------------------- if ("relayConfig" === key) { - initRelays(value); - initRelayConfig(value); + if ($("#relays > div").length) { + return; + } + + if ($("#relayConfig > legend").length) { + return; + } + + let schema = value.schema; + value["relays"].forEach((entries, id) => { + let cfg = fromSchema(entries, schema); + var name = cfg["relayName"]; + if (!cfg.relayName.length) { + cfg.relayName = "Switch #" + id; + } + + initRelay(id, cfg, value); + initRelayConfig(id, cfg, value); + }); return; } @@ -2379,7 +2364,7 @@ $(function() { resetOriginals(); - $(".group-settings").each(function() { + $(".settings-group").each(function() { groupSettingsObserver.observe(this, {childList: true}); }); diff --git a/code/html/index.html b/code/html/index.html index e81bdb22..d3125bab 100644 --- a/code/html/index.html +++ b/code/html/index.html @@ -879,7 +879,7 @@ Networks -
+
@@ -900,7 +900,7 @@
-
+
@@ -941,7 +941,7 @@ Specific topics -
+
@@ -1395,10 +1395,10 @@
Set IDX to 0 to disable notifications from that component.
-
+
-
+
@@ -1510,10 +1510,10 @@
Enter the field number to send each data to, 0 disable notifications from that component.
-
+
-
+
@@ -1608,7 +1608,7 @@ Rules -
+
MQTT @@ -1618,7 +1618,7 @@
Variable Name
-
+
@@ -2036,61 +2036,75 @@
 1 for Monday, 2 for Tuesday etc., comma separated
-
+
+ +
+ +
+
-
- +
+ +
+
- -
- +
+ +
+ +
+ +
- -
- -
- +
+ +
+ +
+ +
- -
- -
- +
+ +
+ +
+ +
- -
- +
- () + ()
-
-
-
-