@@ -30,6 +30,9 @@ private:
3030 byte pin;
3131 String name;
3232 int relayNum; // Added to track relay number
33+ unsigned long timerStart; // When timer was started
34+ int timerDuration; // Duration in seconds
35+ bool timerActive; // If timer is currently running
3336
3437 void loadFromPreferences ()
3538 {
@@ -66,7 +69,8 @@ private:
6669 }
6770
6871public:
69- Relay (byte pinNumber, int num) : pin(pinNumber), relayNum(num) // Simplified constructor
72+ Relay (byte pinNumber, int num) : pin(pinNumber), relayNum(num),
73+ timerStart (0 ), timerDuration(0 ), timerActive(false ) // Simplified constructor
7074 {
7175 pinMode (pin, OUTPUT);
7276 loadFromPreferences ();
@@ -119,6 +123,19 @@ public:
119123 name = newName;
120124 saveToPreferences ();
121125 }
126+
127+ // Add timer methods
128+ void setTimer (int duration, bool start) {
129+ timerDuration = duration;
130+ timerActive = start;
131+ if (start) {
132+ timerStart = millis ();
133+ }
134+ }
135+
136+ int getTimerDuration () { return timerDuration; }
137+ bool isTimerActive () { return timerActive; }
138+ unsigned long getTimerStart () { return timerStart; }
122139};
123140
124141// Initialize preferences once
@@ -285,6 +302,85 @@ void setup()
285302 relays[modeIndex-1 ]->setMode (newMode);
286303 request->send (200 , " text/plain" , " Mode updated" );
287304 });
305+
306+ // Add timer endpoint
307+ String timerEndpoint = " /api/led" + String (i) + " /timer" ;
308+ server.on (timerEndpoint.c_str (), HTTP_POST, [](AsyncWebServerRequest *request) {},
309+ NULL , [modeIndex](AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t /* index*/ , size_t /* total*/ ) {
310+ StaticJsonDocument<200 > doc;
311+ DeserializationError error = deserializeJson (doc, (const char *)data, len);
312+
313+ if (error) {
314+ request->send (400 , " text/plain" , " Invalid JSON" );
315+ return ;
316+ }
317+
318+ if (!doc.containsKey (" duration" ) || !doc.containsKey (" state" )) {
319+ request->send (400 , " text/plain" , " Missing duration or state field" );
320+ return ;
321+ }
322+
323+ int duration = doc[" duration" ].as <int >();
324+ bool state = doc[" state" ].as <bool >();
325+
326+ if (!state) {
327+ // Deactivate timer
328+ relays[modeIndex-1 ]->setTimer (0 , false );
329+ request->send (200 , " text/plain" , " Timer stopped" );
330+ return ;
331+ }
332+
333+ if (duration <= 0 ) {
334+ request->send (400 , " text/plain" , " Invalid duration" );
335+ return ;
336+ }
337+
338+ // Set timer with provided duration
339+ relays[modeIndex-1 ]->setTimer (duration, true );
340+ request->send (200 , " text/plain" , " Timer started" );
341+ });
342+
343+ // Add schedule endpoint
344+ String scheduleEndpoint = " /api/led" + String (i) + " /schedule" ;
345+ server.on (scheduleEndpoint.c_str (), HTTP_POST, [](AsyncWebServerRequest *request) {},
346+ NULL , [modeIndex](AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t /* index*/ , size_t /* total*/ ) {
347+ StaticJsonDocument<200 > doc;
348+ DeserializationError error = deserializeJson (doc, (const char *)data, len);
349+
350+ if (error) {
351+ request->send (400 , " text/plain" , " Invalid JSON" );
352+ return ;
353+ }
354+
355+ if (!doc.containsKey (" onTime" ) || !doc.containsKey (" offTime" )) {
356+ request->send (400 , " text/plain" , " Missing time fields" );
357+ return ;
358+ }
359+
360+ String onTimeStr = doc[" onTime" ].as <String>();
361+ String offTimeStr = doc[" offTime" ].as <String>();
362+
363+ // Convert time strings to integers (e.g., "14:30" -> 1430)
364+ int onTime = (onTimeStr.substring (0 ,2 ).toInt () * 100 ) + onTimeStr.substring (3 ,5 ).toInt ();
365+ int offTime = (offTimeStr.substring (0 ,2 ).toInt () * 100 ) + offTimeStr.substring (3 ,5 ).toInt ();
366+
367+ if (onTime < 0 || onTime > 2359 || offTime < 0 || offTime > 2359 ) {
368+ request->send (400 , " text/plain" , " Invalid time values" );
369+ return ;
370+ }
371+
372+ relays[modeIndex-1 ]->setTimes (onTime, offTime);
373+ request->send (200 , " text/plain" , " Schedule updated" );
374+ });
375+
376+ // Add schedule GET endpoint
377+ String scheduleGetEndpoint = " /api/led" + String (i) + " /schedule" ;
378+ server.on (scheduleGetEndpoint.c_str (), HTTP_GET, [modeIndex](AsyncWebServerRequest *request) {
379+ AsyncResponseStream *response = request->beginResponseStream (" application/json" );
380+ response->print (" {\" onTime\" : " + String (relays[modeIndex-1 ]->getOnTime ()) +
381+ " , \" offTime\" : " + String (relays[modeIndex-1 ]->getOffTime ()) + " }" );
382+ request->send (response);
383+ });
288384 }
289385
290386 // Toggle endpoints for each relay
0 commit comments