From bd0b620b47c7943a4e85d0b433a6e48f54afd3bb Mon Sep 17 00:00:00 2001 From: pagedpenguin251 Date: Sun, 13 Jul 2025 16:32:19 -0600 Subject: [PATCH] Add scheduleing (kinda replaceing macros?) --- wled00/data/settings_time.htm | 5 ++ wled00/schedule.cpp | 105 ++++++++++++++++++++++++++++++++++ wled00/schedule.h | 20 +++++++ wled00/wled.cpp | 3 + wled00/wled.h | 2 + 5 files changed, 135 insertions(+) create mode 100644 wled00/schedule.cpp create mode 100644 wled00/schedule.h diff --git a/wled00/data/settings_time.htm b/wled00/data/settings_time.htm index ae29065ea..8622b79c7 100644 --- a/wled00/data/settings_time.htm +++ b/wled00/data/settings_time.htm @@ -178,6 +178,11 @@ Countdown Goal:
Date: 20--
Time: ::
+

Upload Schedule JSON

+ + +
+ Backup schedule

Macro presets

Macros have moved!
Presets now also can be used as macros to save both JSON and HTTP API commands.
diff --git a/wled00/schedule.cpp b/wled00/schedule.cpp new file mode 100644 index 000000000..0d9685175 --- /dev/null +++ b/wled00/schedule.cpp @@ -0,0 +1,105 @@ +// schedule.cpp + +//TODO: make schedule.json trigger loadshedule(); on upload istead of just once a min (line 50) + +#include "schedule.h" +#include +#include + +#define SCHEDULE_FILE "/schedule.json" + +ScheduleEvent scheduleEvents[MAX_SCHEDULE_EVENTS]; +uint8_t numScheduleEvents = 0; + +bool isTodayInRange(uint8_t sm, uint8_t sd, uint8_t em, uint8_t ed, uint8_t cm, uint8_t cd) +{ + if (sm < em || (sm == em && sd <= ed)) + { + return (cm > sm || (cm == sm && cd >= sd)) && + (cm < em || (cm == em && cd <= ed)); + } + else + { + return (cm > sm || (cm == sm && cd >= sd)) || + (cm < em || (cm == em && cd <= ed)); + } +} + + +// Checks the schedule and applies any events that match the current time and date. + +void checkSchedule() { + static int lastMinute = -1; + + time_t now = localTime; + if (now < 100000) return; + + struct tm* timeinfo = localtime(&now); + int thisMinute = timeinfo->tm_min + timeinfo->tm_hour * 60; + + if (thisMinute == lastMinute) return; + lastMinute = thisMinute; + + + uint8_t cm = timeinfo->tm_mon + 1; // months since Jan (0-11) + uint8_t cd = timeinfo->tm_mday; + uint8_t wday = timeinfo->tm_wday; // days since Sunday (0-6) + uint8_t hr = timeinfo->tm_hour; + uint8_t min = timeinfo->tm_min; + + loadSchedule(); + DEBUG_PRINTF_P(PSTR("[Schedule] Checking schedule at %02u:%02u\n"), hr, min); + + for (uint8_t i = 0; i < numScheduleEvents; i++) + { + const ScheduleEvent &e = scheduleEvents[i]; + if (e.hour != hr || e.minute != min) + continue; + + bool match = false; + if (e.repeatMask && ((e.repeatMask >> wday) & 0x01)) + match = true; + if (e.startMonth) + { + if (isTodayInRange(e.startMonth, e.startDay, e.endMonth, e.endDay, cm, cd)) + match = true; + } + + if (match) + applyPreset(e.presetId); + DEBUG_PRINTF_P(PSTR("[Schedule] Applying preset %u at %02u:%02u\n"), e.presetId, hr, min); + DEBUG_PRINTF_P(PSTR("[Schedule] Checked event %u: match=%d\n"), i, match); + } +} + +void loadSchedule() +{ + if (!WLED_FS.exists(SCHEDULE_FILE)) + return; + File file = WLED_FS.open(SCHEDULE_FILE, "r"); + if (!file) + return; + + DynamicJsonDocument doc(4096); + if (deserializeJson(doc, file)) + { + file.close(); + return; + } + file.close(); + + numScheduleEvents = 0; + for (JsonObject e : doc.as()) + { + if (numScheduleEvents >= MAX_SCHEDULE_EVENTS) + break; + scheduleEvents[numScheduleEvents++] = { + (uint8_t)e["sm"], (uint8_t)e["sd"], // start month, day + (uint8_t)e["em"], (uint8_t)e["ed"], // end month, day + (uint8_t)e["r"], (uint8_t)e["h"], // repeat mask, hour + (uint8_t)e["m"], (uint8_t)e["p"]}; // minute, preset + } + DEBUG_PRINTF_P(PSTR("[Schedule] Loaded %u schedule entries from schedule.json\n"), numScheduleEvents); + +} + diff --git a/wled00/schedule.h b/wled00/schedule.h new file mode 100644 index 000000000..ced0688bc --- /dev/null +++ b/wled00/schedule.h @@ -0,0 +1,20 @@ +// schedule.h +#pragma once + +#include + +#define MAX_SCHEDULE_EVENTS 32 + +struct ScheduleEvent { + uint8_t startMonth; + uint8_t startDay; + uint8_t endMonth; + uint8_t endDay; + uint8_t repeatMask; + uint8_t hour; + uint8_t minute; + uint8_t presetId; +}; + +void loadSchedule(); +void checkSchedule(); diff --git a/wled00/wled.cpp b/wled00/wled.cpp index c372d22ab..d5d634177 100644 --- a/wled00/wled.cpp +++ b/wled00/wled.cpp @@ -54,6 +54,7 @@ void WLED::loop() #endif handleTime(); + checkSchedule(); #ifndef WLED_DISABLE_INFRARED handleIR(); // 2nd call to function needed for ESP32 to return valid results -- should be good for ESP8266, too #endif @@ -526,6 +527,8 @@ void WLED::setup() #if defined(ARDUINO_ARCH_ESP32) && defined(WLED_DISABLE_BROWNOUT_DET) WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 1); //enable brownout detector #endif + + loadSchedule(); } void WLED::beginStrip() diff --git a/wled00/wled.h b/wled00/wled.h index 52bb2f936..a823c87c2 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -66,6 +66,8 @@ #include #include +#include "schedule.h" + // Library inclusions. #include