@@ -697,6 +697,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
697697 // Load timers into new vector-based system
698698 clearTimers ();
699699
700+ // Load regular timers from "ins" array
700701 JsonArray timers = tm[" ins" ];
701702 for (JsonObject timer : timers) {
702703 // Extract timer data from JSON
@@ -705,25 +706,60 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
705706 uint8_t preset = timer[" macro" ] | 0 ;
706707
707708 // Handle weekdays and enabled state
708- uint8_t weekdays = timer[F (" dow" )] | 0 ;
709- weekdays <<= 1 ; // shift to make room for enabled bit
710- bool enabled = timer[" en" ] | false ;
711- if (enabled) weekdays |= 0x01 ; // set enabled bit
709+ uint8_t weekdays = (timer[F (" dow" )] | 0 ) << 1 ; // shift weekdays to upper 7 bits
710+ if (timer[" en" ] | false ) weekdays |= 0x01 ; // set enabled bit if timer is enabled
712711
713- // Handle date range (only for regular timers)
714- uint8_t monthStart = 1 , monthEnd = 12 , dayStart = 1 , dayEnd = 31 ;
715- if (hour < 254 ) { // regular timer
716- JsonObject start = timer[" start" ];
717- JsonObject end = timer[" end" ];
718- monthStart = start[" mon" ] | 1 ;
719- dayStart = start[" day" ] | 1 ;
720- monthEnd = end[" mon" ] | 12 ;
721- dayEnd = end[" day" ] | 31 ;
722- }
712+ // Handle date range for regular timers
713+ JsonObject start = timer[" start" ];
714+ JsonObject end = timer[" end" ];
715+ uint8_t monthStart = start[" mon" ] | 1 ;
716+ uint8_t dayStart = start[" day" ] | 1 ;
717+ uint8_t monthEnd = end[" mon" ] | 12 ;
718+ uint8_t dayEnd = end[" day" ] | 31 ;
723719
724- // Add timer to vector system
720+ // Add regular timer to vector system
725721 addTimer (preset, hour, minute, weekdays, monthStart, monthEnd, dayStart, dayEnd);
726722 }
723+
724+ // Load sunrise/sunset timers from separate "sunrise_sunset" object
725+ JsonObject sunriseSunset = tm[" sunrise_sunset" ];
726+ if (!sunriseSunset.isNull ()) {
727+ // Load sunrise timer
728+ JsonObject sunrise = sunriseSunset[" sunrise" ];
729+ if (!sunrise.isNull ()) {
730+ uint8_t preset = sunrise[" macro" ] | 0 ;
731+ int8_t offset = sunrise[" offset" ] | 0 ;
732+ uint8_t weekdays = (sunrise[F (" dow" )] | 0 ) << 1 ;
733+ if (sunrise[" en" ] | false ) weekdays |= 0x01 ;
734+
735+ JsonObject start = sunrise[" start" ];
736+ JsonObject end = sunrise[" end" ];
737+ uint8_t monthStart = start[" mon" ] | 1 ;
738+ uint8_t dayStart = start[" day" ] | 1 ;
739+ uint8_t monthEnd = end[" mon" ] | 12 ;
740+ uint8_t dayEnd = end[" day" ] | 31 ;
741+
742+ addTimer (preset, TIMER_HOUR_SUNRISE, offset, weekdays, monthStart, monthEnd, dayStart, dayEnd);
743+ }
744+
745+ // Load sunset timer
746+ JsonObject sunset = sunriseSunset[" sunset" ];
747+ if (!sunset.isNull ()) {
748+ uint8_t preset = sunset[" macro" ] | 0 ;
749+ int8_t offset = sunset[" offset" ] | 0 ;
750+ uint8_t weekdays = (sunset[F (" dow" )] | 0 ) << 1 ;
751+ if (sunset[" en" ] | false ) weekdays |= 0x01 ;
752+
753+ JsonObject start = sunset[" start" ];
754+ JsonObject end = sunset[" end" ];
755+ uint8_t monthStart = start[" mon" ] | 1 ;
756+ uint8_t dayStart = start[" day" ] | 1 ;
757+ uint8_t monthEnd = end[" mon" ] | 12 ;
758+ uint8_t dayEnd = end[" day" ] | 31 ;
759+
760+ addTimer (preset, TIMER_HOUR_SUNSET, offset, weekdays, monthStart, monthEnd, dayStart, dayEnd);
761+ }
762+ }
727763
728764 JsonObject ota = doc[" ota" ];
729765 const char * pwd = ota[" psk" ]; // normally not present due to security
@@ -1190,22 +1226,32 @@ void serializeConfig(JsonObject root) {
11901226 goal.add (countdownHour); goal.add (countdownMin); goal.add (countdownSec);
11911227 cntdwn[" macro" ] = macroCountdown;
11921228
1229+ // Separate regular timers and sunrise/sunset timers
11931230 JsonArray timers_ins = timers.createNestedArray (" ins" );
1231+ JsonObject sunrise_sunset = timers.createNestedObject (" sunrise_sunset" );
1232+
1233+ Timer sunriseTimer, sunsetTimer;
1234+ bool hasSunrise = false , hasSunset = false ;
11941235
11951236 // Access the global timers vector from ntp.cpp
11961237 for (const auto & timer : ::timers) {
1197- // Skip completely empty timers (but save sunrise/sunset even if preset=0)
1198- if (timer.preset == 0 && timer.hour < 254 && timer.minute == 0 ) continue ;
1199-
1200- JsonObject timers_ins0 = timers_ins.createNestedObject ();
1201- timers_ins0[" en" ] = timer.isEnabled ();
1202- timers_ins0[F (" hour" )] = timer.hour ;
1203- timers_ins0[" min" ] = timer.minute ;
1204- timers_ins0[" macro" ] = timer.preset ;
1205- timers_ins0[F (" dow" )] = timer.weekdays >> 1 ; // remove enabled bit
1206-
1207- // Add date range for regular timers only
1208- if (timer.isRegular ()) {
1238+ if (timer.isSunrise ()) {
1239+ sunriseTimer = timer;
1240+ hasSunrise = true ;
1241+ } else if (timer.isSunset ()) {
1242+ sunsetTimer = timer;
1243+ hasSunset = true ;
1244+ } else if (timer.isRegular ()) {
1245+ // Skip completely empty regular timers
1246+ if (timer.preset == 0 && timer.minute == 0 ) continue ;
1247+
1248+ JsonObject timers_ins0 = timers_ins.createNestedObject ();
1249+ timers_ins0[" en" ] = timer.isEnabled ();
1250+ timers_ins0[F (" hour" )] = timer.hour ;
1251+ timers_ins0[" min" ] = timer.minute ;
1252+ timers_ins0[" macro" ] = timer.preset ;
1253+ timers_ins0[F (" dow" )] = timer.weekdays >> 1 ; // remove enabled bit
1254+
12091255 JsonObject start = timers_ins0.createNestedObject (" start" );
12101256 start[" mon" ] = timer.monthStart ;
12111257 start[" day" ] = timer.dayStart ;
@@ -1214,6 +1260,36 @@ void serializeConfig(JsonObject root) {
12141260 end[" day" ] = timer.dayEnd ;
12151261 }
12161262 }
1263+
1264+ // Save sunrise timer if it exists
1265+ if (hasSunrise) {
1266+ JsonObject sunrise = sunrise_sunset.createNestedObject (" sunrise" );
1267+ sunrise[" en" ] = sunriseTimer.isEnabled ();
1268+ sunrise[" offset" ] = sunriseTimer.minute ; // offset in minutes
1269+ sunrise[" macro" ] = sunriseTimer.preset ;
1270+ sunrise[F (" dow" )] = sunriseTimer.weekdays >> 1 ; // remove enabled bit
1271+ JsonObject start = sunrise.createNestedObject (" start" );
1272+ start[" mon" ] = sunriseTimer.monthStart ;
1273+ start[" day" ] = sunriseTimer.dayStart ;
1274+ JsonObject end = sunrise.createNestedObject (" end" );
1275+ end[" mon" ] = sunriseTimer.monthEnd ;
1276+ end[" day" ] = sunriseTimer.dayEnd ;
1277+ }
1278+
1279+ // Save sunset timer if it exists
1280+ if (hasSunset) {
1281+ JsonObject sunset = sunrise_sunset.createNestedObject (" sunset" );
1282+ sunset[" en" ] = sunsetTimer.isEnabled ();
1283+ sunset[" offset" ] = sunsetTimer.minute ; // offset in minutes
1284+ sunset[" macro" ] = sunsetTimer.preset ;
1285+ sunset[F (" dow" )] = sunsetTimer.weekdays >> 1 ; // remove enabled bit
1286+ JsonObject start = sunset.createNestedObject (" start" );
1287+ start[" mon" ] = sunsetTimer.monthStart ;
1288+ start[" day" ] = sunsetTimer.dayStart ;
1289+ JsonObject end = sunset.createNestedObject (" end" );
1290+ end[" mon" ] = sunsetTimer.monthEnd ;
1291+ end[" day" ] = sunsetTimer.dayEnd ;
1292+ }
12171293
12181294 JsonObject ota = root.createNestedObject (" ota" );
12191295 ota[F (" lock" )] = otaLock;
0 commit comments