Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
161 changes: 120 additions & 41 deletions wled00/cfg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -694,37 +694,71 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
CJSON(macroCountdown, cntdwn["macro"]);
setCountdown();

// Load timers into new vector-based system
clearTimers();

// Load regular timers from "ins" array
JsonArray timers = tm["ins"];
uint8_t it = 0;
for (JsonObject timer : timers) {
if (it > 9) break;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where do you handle legacy configuration? Consider upgrade path.

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]++;
// Extract timer data from JSON
uint8_t hour = timer[F("hour")] | 0;
int8_t minute = timer["min"] | 0;
uint8_t preset = timer["macro"] | 0;

// Handle weekdays and enabled state
uint8_t weekdays = (timer[F("dow")] | 0) << 1; // shift weekdays to upper 7 bits
if (timer["en"] | false) weekdays |= 0x01; // set enabled bit if timer is enabled

// Handle date range for regular timers
JsonObject start = timer["start"];
JsonObject end = timer["end"];
uint8_t monthStart = start["mon"] | 1;
uint8_t dayStart = start["day"] | 1;
uint8_t monthEnd = end["mon"] | 12;
uint8_t dayEnd = end["day"] | 31;

// Add regular timer to vector system
addTimer(preset, hour, minute, weekdays, monthStart, monthEnd, dayStart, dayEnd);
}

// Load sunrise/sunset timers from separate "sunrise_sunset" object
JsonObject sunriseSunset = tm["sunrise_sunset"];
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to have such long key, as this is not a UI element. Use short keys (not necessarily descriptive) like "ss".

Also. Why would you limit yourself to just one "sunrise" and "sunset" event?
You should be able to schedule different sunrise and sunset events as well.

if (!sunriseSunset.isNull()) {
// Load sunrise timer
JsonObject sunrise = sunriseSunset["sunrise"];
if (!sunrise.isNull()) {
uint8_t preset = sunrise["macro"] | 0;
int8_t offset = sunrise["offset"] | 0;
uint8_t weekdays = (sunrise[F("dow")] | 0) << 1;
if (sunrise["en"] | false) weekdays |= 0x01;

JsonObject start = sunrise["start"];
JsonObject end = sunrise["end"];
uint8_t monthStart = start["mon"] | 1;
uint8_t dayStart = start["day"] | 1;
uint8_t monthEnd = end["mon"] | 12;
uint8_t dayEnd = end["day"] | 31;

addTimer(preset, TIMER_HOUR_SUNRISE, offset, weekdays, monthStart, monthEnd, dayStart, dayEnd);
}
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

// Load sunset timer
JsonObject sunset = sunriseSunset["sunset"];
if (!sunset.isNull()) {
uint8_t preset = sunset["macro"] | 0;
int8_t offset = sunset["offset"] | 0;
uint8_t weekdays = (sunset[F("dow")] | 0) << 1;
if (sunset["en"] | false) weekdays |= 0x01;

JsonObject start = sunset["start"];
JsonObject end = sunset["end"];
uint8_t monthStart = start["mon"] | 1;
uint8_t dayStart = start["day"] | 1;
uint8_t monthEnd = end["mon"] | 12;
uint8_t dayEnd = end["day"] | 31;

addTimer(preset, TIMER_HOUR_SUNSET, offset, weekdays, monthStart, monthEnd, dayStart, dayEnd);
}
it++;
}

JsonObject ota = doc["ota"];
Expand Down Expand Up @@ -1192,25 +1226,70 @@ void serializeConfig(JsonObject root) {
goal.add(countdownHour); goal.add(countdownMin); goal.add(countdownSec);
cntdwn["macro"] = macroCountdown;

// Separate regular timers and sunrise/sunset timers
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 sunrise_sunset = timers.createNestedObject("sunrise_sunset");

Timer sunriseTimer, sunsetTimer;
bool hasSunrise = false, hasSunset = false;

// Access the global timers vector from ntp.cpp
for (const auto& timer : ::timers) {
if (timer.isSunrise()) {
sunriseTimer = timer;
hasSunrise = true;
} else if (timer.isSunset()) {
sunsetTimer = timer;
hasSunset = true;
} else if (timer.isRegular()) {
// Skip completely empty regular timers
if (timer.preset == 0 && timer.minute == 0) continue;

JsonObject timers_ins0 = timers_ins.createNestedObject();
timers_ins0["en"] = timer.isEnabled();
timers_ins0[F("hour")] = timer.hour;
timers_ins0["min"] = timer.minute;
timers_ins0["macro"] = timer.preset;
timers_ins0[F("dow")] = timer.weekdays >> 1; // remove enabled bit

JsonObject start = timers_ins0.createNestedObject("start");
start["mon"] = (timerMonth[i] >> 4) & 0xF;
start["day"] = timerDay[i];
start["mon"] = timer.monthStart;
start["day"] = timer.dayStart;
JsonObject end = timers_ins0.createNestedObject("end");
end["mon"] = timerMonth[i] & 0xF;
end["day"] = timerDayEnd[i];
end["mon"] = timer.monthEnd;
end["day"] = timer.dayEnd;
}
}

// Save sunrise timer if it exists
if (hasSunrise) {
JsonObject sunrise = sunrise_sunset.createNestedObject("sunrise");
sunrise["en"] = sunriseTimer.isEnabled();
sunrise["offset"] = sunriseTimer.minute; // offset in minutes
sunrise["macro"] = sunriseTimer.preset;
sunrise[F("dow")] = sunriseTimer.weekdays >> 1; // remove enabled bit
JsonObject start = sunrise.createNestedObject("start");
start["mon"] = sunriseTimer.monthStart;
start["day"] = sunriseTimer.dayStart;
JsonObject end = sunrise.createNestedObject("end");
end["mon"] = sunriseTimer.monthEnd;
end["day"] = sunriseTimer.dayEnd;
}

// Save sunset timer if it exists
if (hasSunset) {
JsonObject sunset = sunrise_sunset.createNestedObject("sunset");
sunset["en"] = sunsetTimer.isEnabled();
sunset["offset"] = sunsetTimer.minute; // offset in minutes
sunset["macro"] = sunsetTimer.preset;
sunset[F("dow")] = sunsetTimer.weekdays >> 1; // remove enabled bit
JsonObject start = sunset.createNestedObject("start");
start["mon"] = sunsetTimer.monthStart;
start["day"] = sunsetTimer.dayStart;
JsonObject end = sunset.createNestedObject("end");
end["mon"] = sunsetTimer.monthEnd;
end["day"] = sunsetTimer.dayEnd;
}

JsonObject ota = root.createNestedObject("ota");
ota[F("lock")] = otaLock;
Expand Down
Loading