Browse Source

Support restore last schedule (#1948)

* Added restore last schedule support

* Merged RestoreLastScheduleState function into the _schCheck function

* handle lights in restore action

* hide webui chbox when not using scheduler

* use settings instead of struct member, hide under ifdef scheduler_support

* relayLastSchedule uses SCHEDULER_RESTORE_LAST_SCHEDULE as default

* Changed all the variable names to be the same so there would be no confusions

* Fixed client side to create an array from relayLastschedule

* Fixed cosmetic issue with the toggle display in webui

* Fixed variable name and disabled comparison at the end

* Added another check if the switch type is light provider

* Changed variables naming

* Naming mistake
master
foxman69 5 years ago
committed by Max Prokhorov
parent
commit
4343457b9e
5 changed files with 102 additions and 24 deletions
  1. +4
    -0
      code/espurna/config/general.h
  2. +8
    -0
      code/espurna/relay.ino
  3. +70
    -22
      code/espurna/scheduler.ino
  4. +16
    -2
      code/html/custom.js
  5. +4
    -0
      code/html/index.html

+ 4
- 0
code/espurna/config/general.h View File

@ -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
// -----------------------------------------------------------------------------


+ 8
- 0
code/espurna/relay.ino View File

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


+ 70
- 22
code/espurna/scheduler.ino View File

@ -11,6 +11,8 @@ Adapted by Xose Pérez <xose dot perez at gmail dot com>
#include <TimeLib.h>
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);
}
}


+ 16
- 2
code/html/custom.js View File

@ -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;
}
}
<!-- endRemoveIf(!rfm69)-->
@ -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;
}


+ 4
- 0
code/html/index.html View File

@ -1890,6 +1890,10 @@
<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="p-g module module-sch">
<div class="p-u-1 p-u-lg-1-4"><label>Restore last schedule</label></div>
<div><input 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 group</label></div>
<div class="pure-u-1 pure-u-lg-3-4"><input name="mqttGroup" class="pure-u-1" tabindex="0" data="0" action="reconnect" /></div>


Loading…
Cancel
Save