Browse Source

webui: rework initialization for relay and scheduler

Send out keys as schema, fill given template based on the 4 common input types.
Also, refactor relayLastSch into schRestore and move into the schedule template.

Moving relayCount to a wide int, this will probably not build...
dev
Maxim Prokhorov 3 years ago
parent
commit
f5940b7083
5 changed files with 331 additions and 309 deletions
  1. +35
    -35
      code/espurna/relay.cpp
  2. +1
    -1
      code/espurna/relay.h
  3. +126
    -99
      code/espurna/scheduler.cpp
  4. +122
    -137
      code/html/custom.js
  5. +47
    -37
      code/html/index.html

+ 35
- 35
code/espurna/relay.cpp View File

@ -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<uint8_t>(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<uint8_t>(getSetting({"relayTopicMode", id},
_relayMqttTopicMode(id))));
relay.add(static_cast<uint8_t>(getSetting({"relayMqttDisc", id},
_relayMqttDisconnectionStatus(id))));
#endif
relay.add(static_cast<uint8_t>(_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<int>(getSetting({"relayTopicMode", id},
_relayMqttTopicMode(id))));
relay.add(static_cast<int>(getSetting({"relayMqttDisc", id},
_relayMqttDisconnectionStatus(id))));
#endif
for (size_t id = 0; id < relayCount(); ++id) {
desc.add(_relays[id].provider->id());
relay.add(static_cast<uint8_t>(_relays[id].pulse));
relay.add(_relays[id].pulse_ms / 1000.0);
JsonArray& relay = cfg.createNestedArray();
_relayWebSocketRelayConfig(relay, id);
}
}
}


+ 1
- 1
code/espurna/relay.h View File

@ -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();


+ 126
- 99
code/espurna/scheduler.cpp View File

@ -21,16 +21,44 @@ Adapted by Xose Pérez <xose dot perez at gmail dot com>
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);
}
}


+ 122
- 137
code/html/custom.js View File

@ -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<size; ++i) {
var elem = $("input[name='relay'][data='" + i + "']");
var elem = $("input[name='relay'][data-id='" + i + "']");
elem.prop("checked", data.status[i]);
var lock = {
0: false,
@ -1144,54 +1150,18 @@ function createCheckboxes() {
}
function initRelayConfig(data) {
var current = $("#relayConfig > 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(
$("<option></option>")
.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(
$("<option></option>")
.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<value.size; ++i) {
// XXX: no
var sch_map = {};
Object.keys(value).forEach(function(key) {
if ("size" == key) return;
if ("max" == key) return;
sch_map[key] = value[key][i];
});
addSchedule(sch_map);
}
if ("schConfig" === key) {
$("#schedules")
.attr("data-settings-max", value.max);
let schema = value.schema;
value["schedules"].forEach((entries, id) => {
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});
});


+ 47
- 37
code/html/index.html View File

@ -879,7 +879,7 @@
<legend>Networks</legend>
<div id="networks" class="group-settings" data-settings-target="ssid pass" ></div>
<div id="networks" class="settings-group" data-settings-target="ssid pass" ></div>
<button type="button" class="pure-button button-add-network">Add network</button>
@ -900,7 +900,7 @@
<fieldset>
<div id="schedules" class="group-settings" data-settings-max="10" data-settings-target="schSwitch schType" ></div>
<div id="schedules" class="settings-group" data-settings-max="10" data-settings-target="schSwitch schType" ></div>
<button type="button" class="pure-button button-add-switch-schedule module module-relay">Add switch schedule</button>
<!-- removeIf(!light) -->
@ -941,7 +941,7 @@
<legend>Specific topics</legend>
<div id="mapping" class="group-settings" ></div>
<div id="mapping" class="settings-group" ></div>
<button type="button" class="pure-button button-add-mapping">Add</button>
@ -1395,10 +1395,10 @@
<div class="pure-u-1 hint">Set IDX to 0 to disable notifications from that component.</div>
</div>
<div id="dczRelays" class="group-settings" ></div>
<div id="dczRelays" class="settings-group" ></div>
<!-- removeIf(!sensor) -->
<div id="dczMagnitudes" class="group-settings" ></div>
<div id="dczMagnitudes" class="settings-group" ></div>
<!-- endRemoveIf(!sensor) -->
</fieldset>
@ -1510,10 +1510,10 @@
<div class="pure-u-1 hint">Enter the field number to send each data to, 0 disable notifications from that component.</div>
</div>
<div id="tspkRelays" class="group-settings" ></div>
<div id="tspkRelays" class="settings-group" ></div>
<!-- removeIf(!sensor) -->
<div id="tspkMagnitudes" class="group-settings" ></div>
<div id="tspkMagnitudes" class="settings-group" ></div>
<!-- endRemoveIf(!sensor) -->
</fieldset>
@ -1608,7 +1608,7 @@
<legend>Rules</legend>
<div id="rpnRules" class="group-settings" data-settings-target="rpnRule" ></div>
<div id="rpnRules" class="settings-group" data-settings-target="rpnRule" ></div>
<button type="button" class="pure-button button-add-rpnrule">Add</button>
<legend>MQTT</legend>
@ -1618,7 +1618,7 @@
<div class="pure-u-1-3">Variable Name</div>
</div>
<div id="rpnTopics" class="group-settings" data-settings-target="rpnTopic" ></div>
<div id="rpnTopics" class="settings-group" data-settings-target="rpnTopic" ></div>
<button type="button" class="pure-button button-add-rpntopic">Add</button>
</fieldset>
@ -2036,61 +2036,75 @@
</div>
<div class="pure-u-3-5 pure-u-lg-1-2 hint center">&nbsp;1 for Monday, 2 for Tuesday etc., comma separated</div>
<div id="schActionDiv" class="pure-u-1">
<div id="schActionDiv" class="pure-u-1 pure-u-lg-1">
</div>
<label class="pure-u-1 pure-u-lg-1-4">Restore on boot</label>
<div class="pure-u-1 pure-u-lg-3-4"><input type="checkbox" name="schRestore" /></div>
<div class="pure-u-0 pure-u-lg-1-2"></div>
<label class="pure-u-1 pure-u-lg-1-4">Enabled</label>
<div class="pure-u-1 pure-u-lg-3-4"><input type="checkbox" name="schEnabled" /></div>
<div class="pure-u-1 pure-u-lg-1-2"></div>
<button class="pure-button button-del-schedule" type="button">Delete schedule</button>
<div class="pure-u-1 pure-u-lg-1-4"></div>
<button class="pure-button button-del-schedule" type="button">Delete schedule</button>
</div>
<div class="pure-u-0 pure-u-lg-3-4"></div>
</div>
</div>
<div id="switchActionTemplate" class="template">
<label class="pure-u-1 pure-u-lg-1-4">Action</label>
<div class="pure-u-1 pure-u-lg-1-5">
<select class="pure-u-1 pure-u-lg-23-24" name="schAction" haschanged="true">
<option value="0">Turn OFF</option>
<option value="1">Turn ON</option>
<option value="2">Toggle</option>
</select>
<div class="pure-form pure-form-aligned">
<label class="pure-u-1 pure-u-lg-1-4">Action</label>
<div class="pure-u-1 pure-u-lg-1-5">
<select class="pure-u-1 pure-u-lg-23-24" name="schAction" haschanged="true">
<option value="0">Turn OFF</option>
<option value="1">Turn ON</option>
<option value="2">Toggle</option>
</select>
</div>
<select class="pure-u-1 pure-u-lg-1-5 isrelay" name="schSwitch" ></select>
<input type="hidden" name="schType" value="1">
</div>
<select class="pure-u-1 pure-u-lg-1-5 isrelay" name="schSwitch" ></select>
<input type="hidden" name="schType" value="1">
</div>
<!-- removeIf(!light) -->
<div id="lightActionTemplate" class="template">
<label class="pure-u-1 pure-u-lg-1-4">Brightness</label>
<div class="pure-u-1 pure-u-lg-1-5">
<input class="pure-u-2-3" name="schAction" type="number" min="0" step="1" max="255" value="0" />
<div class="pure-form pure-form-aligned">
<label class="pure-u-1 pure-u-lg-1-4">Brightness</label>
<div class="pure-u-1 pure-u-lg-1-5">
<input class="pure-u-2-3" name="schAction" type="number" min="0" step="1" max="255" value="0" />
</div>
<select class="pure-u-1 pure-u-lg-1-5 islight" name="schSwitch" ></select>
<input type="hidden" name="schType" value="2">
</div>
<select class="pure-u-1 pure-u-lg-1-5 islight" name="schSwitch" ></select>
<input type="hidden" name="schType" value="2">
</div>
<!-- endRemoveIf(!light) -->
<!-- removeIf(!curtain) -->
<div id="curtainActionTemplate" class="template">
<label class="pure-u-1 pure-u-lg-1-4">Curtain position (0 = open to 100 = closed)</label>
<div class="pure-u-1 pure-u-lg-1-5">
<input class="pure-u-2-3" name="schAction" type="number" min="0" step="1" max="100" value="0" />
<div class="pure-form pure-form-aligned">
<label class="pure-u-1 pure-u-lg-1-4">Curtain position (0 = open to 100 = closed)</label>
<div class="pure-u-1 pure-u-lg-1-5">
<input class="pure-u-2-3" name="schAction" type="number" min="0" step="1" max="100" value="0" />
</div>
<select class="pure-u-1 pure-u-lg-1-5 iscurtain" name="schSwitch" ></select>
<input type="hidden" name="schType" value="3">
</div>
<select class="pure-u-1 pure-u-lg-1-5 iscurtain" name="schSwitch" ></select>
<input type="hidden" name="schType" value="3">
</div>
<!-- endRemoveIf(!curtain) -->
<div id="relayTemplate" class="template">
<div class="pure-g">
<label class="pure-u-1 pure-u-lg-1-4"><span class="relay-name"></span></label>
<label class="pure-u-1 pure-u-lg-1-4"><span class="relayName"></span></label>
<div><input name="relay" type="checkbox" on="ON" off="OFF" /></div>
</div>
</div>
<div id="relayConfigTemplate" class="template">
<legend><span class="name"></span> (<span class="prov"></span>)</legend>
<legend><span class="relayName"></span> (<span class="relayProv"></span>)</legend>
<div class="pure-g">
<div class="pure-u-1 pure-u-lg-1-4"><label>Boot mode</label></div>
<select class="pure-u-1 pure-u-lg-3-4" name="relayBoot">
@ -2114,10 +2128,6 @@
<div class="pure-u-1 pure-u-lg-1-4"><label>Pulse time (s)</label></div>
<div class="pure-u-1 pure-u-lg-1-4"><input name="relayTime" class="pure-u-1" type="number" min="0" step="0.1" max="3600" /></div>
</div>
<div class="pure-g module module-sch">
<div class="pure-u-1 pure-u-lg-1-4"><label>Restore last schedule</label></div>
<div><input name="relayLastSch" data-settings-real-name="relayLastSch" type="checkbox" /></div>
</div>
<div class="pure-g module module-mqtt">
<div class="pure-u-1 pure-u-lg-1-4"><label>MQTT topic subscription</label></div>
<div class="pure-u-1 pure-u-lg-3-4"><input name="relayTopicSub" class="pure-u-1" action="reconnect" /></div>


Loading…
Cancel
Save