diff --git a/code/espurna/config/general.h b/code/espurna/config/general.h index f76a7bf8..f6a6a787 100644 --- a/code/espurna/config/general.h +++ b/code/espurna/config/general.h @@ -1395,6 +1395,10 @@ #define SCHEDULER_MAX_SCHEDULES 10 // Max schedules alowed #endif +#ifndef SCHEDULER_RESTORE_LAST_SCHEDULE +#define SCHEDULER_RESTORE_LAST_SCHEDULE 0 // Restore the last schedule state on the device boot +#endif + // ----------------------------------------------------------------------------- // NTP // ----------------------------------------------------------------------------- diff --git a/code/espurna/relay.ino b/code/espurna/relay.ino index 298f2857..c8e2d585 100644 --- a/code/espurna/relay.ino +++ b/code/espurna/relay.ino @@ -732,6 +732,10 @@ void _relayWebSocketSendRelays(JsonObject& root) { JsonArray& pulse = relays.createNestedArray("pulse"); JsonArray& pulse_time = relays.createNestedArray("pulse_time"); + #if SCHEDULER_SUPPORT + JsonArray& sch_last = relays.createNestedArray("sch_last"); + #endif + #if MQTT_SUPPORT JsonArray& group = relays.createNestedArray("group"); JsonArray& group_sync = relays.createNestedArray("group_sync"); @@ -748,6 +752,10 @@ void _relayWebSocketSendRelays(JsonObject& root) { pulse.add(_relays[i].pulse); pulse_time.add(_relays[i].pulse_ms / 1000.0); + #if SCHEDULER_SUPPORT + sch_last.add(getSetting("relayLastSch", i, SCHEDULER_RESTORE_LAST_SCHEDULE).toInt()); + #endif + #if MQTT_SUPPORT group.add(getSetting("mqttGroup", i, "")); group_sync.add(getSetting("mqttGroupSync", i, 0).toInt()); diff --git a/code/espurna/scheduler.ino b/code/espurna/scheduler.ino index ac62069c..cf95310c 100644 --- a/code/espurna/scheduler.ino +++ b/code/espurna/scheduler.ino @@ -11,6 +11,8 @@ Adapted by Xose PĂ©rez #include +int _sch_restore = 0; + // ----------------------------------------------------------------------------- #if WEB_SUPPORT @@ -136,10 +138,36 @@ int _schMinutesLeft(time_t t, unsigned char schedule_hour, unsigned char schedul return (schedule_hour - now_hour) * 60 + schedule_minute - now_minute; } -void _schCheck() { +void _schAction(int sch_id, int sch_action, int sch_switch) { + unsigned char sch_type = getSetting("schType", sch_id, SCHEDULER_TYPE_SWITCH).toInt(); + + if (SCHEDULER_TYPE_SWITCH == sch_type) { + DEBUG_MSG_P(PSTR("[SCH] Switching switch %d to %d\n"), sch_switch, sch_action); + if (sch_action == 2) { + relayToggle(sch_switch); + } else { + relayStatus(sch_switch, sch_action); + } + } + + #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(true, true); + } + #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) { time_t local_time = now(); time_t utc_time = ntpLocal2UTC(local_time); + int minimum_restore_time = -1440; + int saved_action = -1; + int saved_sch = -1; // Check schedules for (unsigned char i = 0; i < SCHEDULER_MAX_SCHEDULES; i++) { @@ -154,36 +182,39 @@ void _schCheck() { bool sch_utc = getSetting("schUTC", i, 0).toInt() == 1; time_t t = sch_utc ? utc_time : local_time; + if (daybefore > 0) { + unsigned char now_hour = hour(t); + unsigned char now_minute = minute(t); + unsigned char now_sec = second(t); + t = t - ((now_hour * 3600) + ((now_minute + 1) * 60) + now_sec + (daybefore * 86400)); + } + String sch_weekdays = getSetting("schWDs", i, ""); if (_schIsThisWeekday(t, sch_weekdays)) { int sch_hour = getSetting("schHour", i, 0).toInt(); int sch_minute = getSetting("schMinute", i, 0).toInt(); int minutes_to_trigger = _schMinutesLeft(t, sch_hour, sch_minute); + int sch_action = getSetting("schAction", i, 0).toInt(); + unsigned char sch_type = getSetting("schType", i, SCHEDULER_TYPE_SWITCH).toInt(); - if (minutes_to_trigger == 0) { - - unsigned char sch_type = getSetting("schType", i, SCHEDULER_TYPE_SWITCH).toInt(); + if (sch_type == SCHEDULER_TYPE_SWITCH && sch_switch == relay && 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 (SCHEDULER_TYPE_SWITCH == sch_type) { - int sch_action = getSetting("schAction", i, 0).toInt(); - DEBUG_MSG_P(PSTR("[SCH] Switching switch %d to %d\n"), sch_switch, sch_action); - if (sch_action == 2) { - relayToggle(sch_switch); - } else { - relayStatus(sch_switch, sch_action); - } + #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) { + minimum_restore_time = minutes_to_trigger; + saved_action = sch_action; + saved_sch = i; } + #endif - #if LIGHT_PROVIDER != LIGHT_PROVIDER_NONE - if (SCHEDULER_TYPE_DIM == sch_type) { - int sch_brightness = getSetting("schAction", i, -1).toInt(); - DEBUG_MSG_P(PSTR("[SCH] Set channel %d value to %d\n"), sch_switch, sch_brightness); - lightChannel(sch_switch, sch_brightness); - lightUpdate(true, true); - } - #endif + if (minutes_to_trigger == 0 && relay == -1) { + _schAction(i, sch_action, sch_switch); DEBUG_MSG_P(PSTR("[SCH] Schedule #%d TRIGGERED!!\n"), i); // Show minutes to trigger every 15 minutes @@ -191,7 +222,7 @@ void _schCheck() { // 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) { + } else if (minutes_to_trigger > 0 && relay == -1) { #if DEBUG_SUPPORT if ((minutes_to_trigger % 15 == 0) || (minutes_to_trigger < 15)) { @@ -208,6 +239,15 @@ void _schCheck() { } + if (daybefore >= 0 && daybefore < 7 && minimum_restore_time == -1440 && saved_action == -1) { + _schCheck(relay, ++daybefore); + return; + } + + if (minimum_restore_time != -1440 && saved_action != -1 && saved_sch != -1) { + _schAction(saved_sch, saved_action, relay); + } + } void _schLoop() { @@ -215,12 +255,20 @@ void _schLoop() { // Check time has been sync'ed if (!ntpSynced()) return; + if (_sch_restore == 0) { + for (int i = 0; i < _relays.size(); i++){ + if (getSetting("relayLastSch", i, SCHEDULER_RESTORE_LAST_SCHEDULE).toInt() == 1) + _schCheck(i, 0); + } + _sch_restore = 1; + } + // Check schedules every minute at hh:mm:00 static unsigned long last_minute = 60; unsigned char current_minute = minute(); if (current_minute != last_minute) { last_minute = current_minute; - _schCheck(); + _schCheck(-1, -1); } } diff --git a/code/html/custom.js b/code/html/custom.js index 6dc611a6..dc284624 100644 --- a/code/html/custom.js +++ b/code/html/custom.js @@ -250,7 +250,7 @@ function addValue(data, name, value) { var is_group = [ "ssid", "pass", "gw", "mask", "ip", "dns", "schEnabled", "schSwitch","schAction","schType","schHour","schMinute","schWDs","schUTC", - "relayBoot", "relayPulse", "relayTime", + "relayBoot", "relayPulse", "relayTime", "relayLastSch", "mqttGroup", "mqttGroupSync", "relayOnDisc", "dczRelayIdx", "dczMagnitude", "tspkRelay", "tspkMagnitude", @@ -265,6 +265,11 @@ function addValue(data, name, value) { name = "adminPass"; } + // join all relayLastSch values + if (name.startsWith("relayLastSch")) { + name = "relayLastSch"; + } + if (name in data) { if (!Array.isArray(data[name])) { data[name] = [data[name]]; @@ -1025,6 +1030,10 @@ function initRelayConfig(data) { $("select[name='relayBoot']", line).val(data.boot[i]); $("select[name='relayPulse']", line).val(data.pulse[i]); $("input[name='relayTime']", line).val(data.pulse_time[i]); + $("input[name='relayLastSch']", line).prop('checked', data.sch_last[i]); + $("input[name='relayLastSch']", line).attr("id", "relayLastSch" + i); + $("input[name='relayLastSch']", line).attr("name", "relayLastSch" + i); + $("input[name='relayLastSch" + i + "']", line).next().attr("for","relayLastSch" + (i)); if ("group" in data) { $("input[name='mqttGroup']", line).val(data.group[i]); @@ -1459,7 +1468,7 @@ function processData(data) { }); } return; - } + } @@ -1702,6 +1711,11 @@ function processData(data) { var position = key.indexOf("Visible"); if (position > 0 && position === key.length - 7) { var module = key.slice(0,-7); + if (module == "sch") { + $("li.module-" + module).css("display", "inherit"); + $("div.module-" + module).css("display", "flex"); + return; + } $(".module-" + module).css("display", "inherit"); return; } diff --git a/code/html/index.html b/code/html/index.html index 3517c6f7..c82a0ddd 100644 --- a/code/html/index.html +++ b/code/html/index.html @@ -1890,6 +1890,10 @@
+
+
+
+