diff --git a/usermods/deep_sleep/deep_sleep.cpp b/usermods/deep_sleep/deep_sleep.cpp index cff40f86de..c110e562c6 100644 --- a/usermods/deep_sleep/deep_sleep.cpp +++ b/usermods/deep_sleep/deep_sleep.cpp @@ -89,28 +89,29 @@ class DeepSleepUsermod : public Usermod { int currentWeekday = weekdayMondayFirst(); // 1=Monday ... 7=Sunday int minDifference = INT_MAX; - for (uint8_t i = 0; i < 8; i++) { - // check if timer is enabled and date is in range, also wakes up if no macro is used - if ((timerWeekday[i] & 0x01) && isTodayInDateRange(((timerMonth[i] >> 4) & 0x0F), timerDay[i], timerMonth[i] & 0x0F, timerDayEnd[i])) { + for (size_t i = 0; i < timers.size(); i++) { + const Timer& t = timers[i]; + // only regular enabled timers with valid date range can be used for wake scheduling + if (!t.isEnabled() || !t.isRegular()) continue; + if (!isTodayInDateRange(t.monthStart, t.dayStart, t.monthEnd, t.dayEnd)) continue; - // if timer is enabled (bit0 of timerWeekday) and date is in range, check all weekdays it is set for - for (int dayOffset = 0; dayOffset < 7; dayOffset++) { - int checkWeekday = ((currentWeekday + dayOffset) % 7); // 1-7, check all weekdays starting from today - if (checkWeekday == 0) { - checkWeekday = 7; // sunday is 7 not 0 - } + // check all weekdays for the current timer, starting from today + for (int dayOffset = 0; dayOffset < 7; dayOffset++) { + int checkWeekday = (currentWeekday + dayOffset) % 7; // 1-7, check all weekdays starting from today + if (checkWeekday == 0) { + checkWeekday = 7; // sunday is 7 not 0 + } - int targetHour = timerHours[i]; - int targetMinute = timerMinutes[i]; - if ((timerWeekday[i] >> (checkWeekday)) & 0x01) { - if (dayOffset == 0 && (targetHour < currentHour || (targetHour == currentHour && targetMinute <= currentMinute))) - continue; // skip if time has already passed today + int targetHour = t.hour; + int targetMinute = t.minute; + if ((t.weekdays >> checkWeekday) & 0x01) { + if (dayOffset == 0 && (targetHour < currentHour || (targetHour == currentHour && targetMinute <= currentMinute))) + continue; // skip if time has already passed today - int timeDifference = calculateTimeDifference(currentHour, currentMinute, targetHour + (dayOffset * 24), targetMinute); - if (timeDifference < minDifference) { - minDifference = timeDifference; - wakeupPreset = timerMacro[i]; - } + int timeDifference = calculateTimeDifference(currentHour, currentMinute, targetHour + (dayOffset * 24), targetMinute); + if (timeDifference < minDifference) { + minDifference = timeDifference; + wakeupPreset = t.preset; } } } diff --git a/wled00/cfg.cpp b/wled00/cfg.cpp index 4f131cab96..f628dfa557 100644 --- a/wled00/cfg.cpp +++ b/wled00/cfg.cpp @@ -689,37 +689,28 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { CJSON(macroCountdown, cntdwn["macro"]); setCountdown(); - JsonArray timers = tm["ins"]; - uint8_t it = 0; - for (JsonObject timer : timers) { - if (it > 9) break; - if (it<8 && timer[F("hour")]==255) it=8; // hour==255 -> sunrise/sunset - CJSON(timerHours[it], timer[F("hour")]); - CJSON(timerMinutes[it], timer["min"]); - CJSON(timerMacro[it], timer["macro"]); - - byte dowPrev = timerWeekday[it]; - //note: act is currently only 0 or 1. - //the reason we are not using bool is that the on-disk type in 0.11.0 was already int - int actPrev = timerWeekday[it] & 0x01; - CJSON(timerWeekday[it], timer[F("dow")]); - if (timerWeekday[it] != dowPrev) { //present in JSON - timerWeekday[it] <<= 1; //add active bit - int act = timer["en"] | actPrev; - if (act) timerWeekday[it]++; - } - if (it<8) { - JsonObject start = timer["start"]; - byte startm = start["mon"]; - if (startm) timerMonth[it] = (startm << 4); - CJSON(timerDay[it], start["day"]); - JsonObject end = timer["end"]; - CJSON(timerDayEnd[it], end["day"]); - byte endm = end["mon"]; - if (startm) timerMonth[it] += endm & 0x0F; - if (!(timerMonth[it] & 0x0F)) timerMonth[it] += 12; //default end month to 12 + JsonArray timersArray = tm["ins"]; + if (!timersArray.isNull()) { + clearTimers(); + for (JsonObject timer : timersArray) { + uint8_t h = timer[F("hour")] | 0; + int8_t m = timer[F("min")] | 0; + uint8_t p = timer[F("macro")] | 0; + uint8_t dow = timer[F("dow")] | 127; + uint8_t wd = (dow << 1) | ((timer[F("en")] | 0) ? 1 : 0); + uint8_t ms = 1, me = 12, ds = 1, de = 31; + JsonObject start = timer[F("start")]; + if (!start.isNull()) { + ms = start[F("mon")] | 1; + ds = start[F("day")] | 1; + } + JsonObject end = timer[F("end")]; + if (!end.isNull()) { + me = end[F("mon")] | 12; + de = end[F("day")] | 31; + } + addTimer(p, h, m, wd, ms, me, ds, de); } - it++; } JsonObject ota = doc["ota"]; @@ -1216,23 +1207,21 @@ void serializeConfig(JsonObject root) { cntdwn["macro"] = macroCountdown; JsonArray timers_ins = timers.createNestedArray("ins"); - - for (unsigned i = 0; i < 10; i++) { - if (timerMacro[i] == 0 && timerHours[i] == 0 && timerMinutes[i] == 0) continue; // sunrise/sunset get saved always (timerHours=255) - JsonObject timers_ins0 = timers_ins.createNestedObject(); - timers_ins0["en"] = (timerWeekday[i] & 0x01); - timers_ins0[F("hour")] = timerHours[i]; - timers_ins0["min"] = timerMinutes[i]; - timers_ins0["macro"] = timerMacro[i]; - timers_ins0[F("dow")] = timerWeekday[i] >> 1; - if (i<8) { - JsonObject start = timers_ins0.createNestedObject("start"); - start["mon"] = (timerMonth[i] >> 4) & 0xF; - start["day"] = timerDay[i]; - JsonObject end = timers_ins0.createNestedObject("end"); - end["mon"] = timerMonth[i] & 0xF; - end["day"] = timerDayEnd[i]; - } + for (size_t i = 0; i < ::timers.size(); i++) { + const Timer& t = ::timers[i]; + if (t.preset == 0 && t.hour == 0 && t.minute == 0) continue; + JsonObject ti = timers_ins.createNestedObject(); + ti[F("en")] = t.isEnabled() ? 1 : 0; + ti[F("hour")] = t.hour; + ti[F("min")] = t.minute; + ti[F("macro")] = t.preset; + ti[F("dow")] = t.weekdays >> 1; + JsonObject start = ti.createNestedObject(F("start")); + start[F("mon")] = t.monthStart; + start[F("day")] = t.dayStart; + JsonObject end = ti.createNestedObject(F("end")); + end[F("mon")] = t.monthEnd; + end[F("day")] = t.dayEnd; } JsonObject ota = root.createNestedObject("ota"); diff --git a/wled00/const.h b/wled00/const.h index e6abd2b5db..6311bfe509 100644 --- a/wled00/const.h +++ b/wled00/const.h @@ -59,6 +59,7 @@ constexpr size_t FIXED_PALETTE_COUNT = DYNAMIC_PALETTE_COUNT + FASTLED_PALETTE_C #define WLED_MAX_RMT_CHANNELS 0 // ESP8266 does not have RMT nor I2S #define WLED_MAX_I2S_CHANNELS 0 #define WLED_MAX_ANALOG_CHANNELS 5 + #define WLED_MAX_TIMERS 16 // reduced limit for ESP8266 due to memory constraints #define WLED_PLATFORM_ID 0 // used in UI to distinguish ESP types, needs a proper fix! #else #if !defined(LEDC_CHANNEL_MAX) || !defined(LEDC_SPEED_MODE_MAX) @@ -86,6 +87,7 @@ constexpr size_t FIXED_PALETTE_COUNT = DYNAMIC_PALETTE_COUNT + FASTLED_PALETTE_C //#define WLED_MAX_ANALOG_CHANNELS 16 #define WLED_PLATFORM_ID 4 // used in UI to distinguish ESP type in UI, needs a proper fix! #endif + #define WLED_MAX_TIMERS 64 // maximum number of timers #define WLED_MAX_DIGITAL_CHANNELS (WLED_MAX_RMT_CHANNELS + WLED_MAX_I2S_CHANNELS) #endif // WLED_MAX_BUSSES was used to define the size of busses[] array which is no longer needed diff --git a/wled00/data/common.js b/wled00/data/common.js index a6223daa7c..e12ddf2df6 100644 --- a/wled00/data/common.js +++ b/wled00/data/common.js @@ -90,7 +90,7 @@ function loadJS(FILE_URL, async = true, preGetV = undefined, postGetV = undefine scE.setAttribute("type", "text/javascript"); scE.setAttribute("async", async); d.body.appendChild(scE); - // success event + // success event scE.addEventListener("load", () => { //console.log("File loaded"); if (preGetV) preGetV(); diff --git a/wled00/data/settings_time.htm b/wled00/data/settings_time.htm index b7848b862b..ab2c4a7fc0 100644 --- a/wled00/data/settings_time.htm +++ b/wled00/data/settings_time.htm @@ -8,6 +8,13 @@