443 lines
20 KiB
C++
443 lines
20 KiB
C++
#include "esp_system.h"
|
||
#include "sntp.h"
|
||
#include "time.h"
|
||
#include <WiFi.h>
|
||
#include <WiFiUdp.h>
|
||
#include <Preferences.h>
|
||
#include "scheduler.h"
|
||
#include "scheduler_prefs.h"
|
||
|
||
|
||
// --------------------------------------------
|
||
// Init const and global objects
|
||
// --------------------------------------------
|
||
|
||
|
||
const char* html_app="<html><head><title>ESP32 timed Switch</title><script src=\"https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.8.3/angular.js\"></script><link rel=\"manifest\" href=\"manifest.json\" /><meta charset=\"UTF-8\"></head><body><h1>Scheduler</h1><script>class Schedule {constructor(scheduleArray) {if (scheduleArray && scheduleArray.length === 24) {this.schedule = scheduleArray.slice();} else {this.schedule = new Array(24).fill(0x000);}}loadFromArrayBuffer = function(buffer) {var view = new DataView(buffer);for (var i = 0; i < 24; i++) {this.schedule[i] = view.getUint16(i * 2, true);}};updateSegment(hour, segment, state) {if (hour < 0 || hour >= 24) {throw new Error('Hour must be between 0 and 23.');}if (segment < 0 || segment >= 12) {throw new Error('Segment must be between 0 and 11.');}const bitPosition = 11 - segment;if (state) {this.schedule[hour] |= (1 << bitPosition);} else {this.schedule[hour] &= ~(1 << bitPosition);}}serializeForDisplay() {return this.schedule.map(hour => {if (hour === 0xFFF) {return { displayValue: ' ', class: 'on' };} else if (hour === 0x00) {return { displayValue: ' ', class: 'off' };} else {return { displayValue: ' ', class: 'partial' };}});}prepareEditMatrix() {const editMatrix = [];for (let hour = 0; hour < 24; hour++) {const hourSegments = [];for (let segment = 0; segment < 12; segment++) {hourSegments.push({value: (this.schedule[hour] & (1 << segment)) !== 0 ? 1 : 0});}editMatrix.push(hourSegments.reverse());}return editMatrix;}updateFromEditMatrix(editMatrix) {for (let hour = 0; hour < 24; hour++) {let hourValue = 0;for (let segment = 0; segment < 12; segment++) {if (editMatrix[hour][11 - segment].value) {hourValue |= (1 << segment);}}this.schedule[hour] = hourValue;}}serializeToArrayBuffer = function() {var buffer = new ArrayBuffer(24 * 2);var view = new DataView(buffer);for (var i = 0; i < 24; i++) {view.setUint8( i*2 , (this.schedule[i] & 65280) >> 8, true);view.setUint8( i*2 + 1, this.schedule[i] & 255 , true);}return buffer;};}var app = angular.module('plugSchedulerApp', []);app.value('api_host', window.location.host);app.factory(\"data\", function(){var sharedData = { api_host: window.location.host};return {getSharedData: function () {return sharedData;}};});app.controller('ApiHostController', ['$scope', 'api_host', 'data', function( $scope, api_host, data) {var ctrl = this;$scope.data = data.getSharedData();window.ctrl = $scope}]);app.controller('PlugScheduleController', ['$scope', '$http', 'data', function( $scope, $http, data) {var ctrl = this;ctrl.editMode = false;$scope.data = data.getSharedData();ctrl.$onInit = function() {ctrl.scheduleObj = new Schedule();ctrl.getSchedule();};ctrl.getSchedule = function() {if (ctrl.plugId === undefined) {return;}var url = `http://${$scope.data.api_host}/api/schedule/${ctrl.plugId}`;$http.get(url, { responseType: 'arraybuffer' }).then(function(response) {ctrl.scheduleObj.loadFromArrayBuffer(response.data);ctrl.displaySchedule = ctrl.scheduleObj.serializeForDisplay();}).catch(function(error) {console.error('Error fetching schedule:', error);});};ctrl.modifySchedule = function() {ctrl.editMode = true;ctrl.editMatrix = ctrl.scheduleObj.prepareEditMatrix();};ctrl.saveSchedule = function() {ctrl.editMode = false;ctrl.scheduleObj.updateFromEditMatrix(ctrl.editMatrix);ctrl.updateSchedule();};ctrl.updateSchedule = function() {var url = `http://${$scope.data.api_host}/api/schedule/${ctrl.plugId}`;var serializedSchedule = ctrl.scheduleObj.serializeToArrayBuffer();$http.post(url, serializedSchedule, {headers: {'Content-Type': 'application/octet-stream'},responseType: 'arraybuffer',transformRequest: []}).then(function(response) {console.log(\"successfully updated\");ctrl.displaySchedule = ctrl.scheduleObj.serializeForDisplay();}, function(error) {alert('Error updating schedule:', error);});};ctrl.checkAll = function(hourIndex) {ctrl.editMatrix[hourIndex].forEach(segment => {segment.value = 1;});};ctrl.uncheckAll = function(hourIndex) {ctrl.editMatrix[hourIndex].forEach(segment => {segment.value = 0;});};ctrl.invertAll = function(hourIndex) {ctrl.editMatrix[hourIndex].forEach(segment => {var inverted = Math.abs( segment.value - 1);segment.value = inverted;});};ctrl.checkPattern = function(hourIndex, results) {for( index = 0; index < ctrl.editMatrix[hourIndex].length; index++){ctrl.editMatrix[hourIndex][index] = { value : results[index] };}};ctrl.checkHalf = function(hourIndex) {ctrl.checkPattern( hourIndex, [1,1,1,1,1,1,0,0,0,0,0,0]);};ctrl.checkFourth = function(hourIndex) {ctrl.checkPattern( hourIndex, [1,1,1,0,0,0,1,1,1,0,0,0]);};ctrl.checkSixth = function(hourIndex) {ctrl.checkPattern( hourIndex, [1,1,0,0,1,1,0,0,1,1,0,0]);};ctrl.checkTwelveth = function(hourIndex) {ctrl.checkPattern( hourIndex, [1,0,1,0,1,0,1,0,1,0,1,0]);};}]);app.component('plugScheduleWidget', {bindings: {plugId: '<'},template: `<div class=\"plug-schedule-widget\"><h3>Plug {{ $ctrl.plugId }}</h3><div ng-if=\"!$ctrl.editMode\"><div ng-repeat=\"hour in $ctrl.displaySchedule track by $index\" class=\"hour-cell\" ng-class=\"hour.class\">{{ hour.displayValue }}</div><button class=\"modify\" ng-click=\"$ctrl.modifySchedule()\">Modify</button></div><div ng-if=\"$ctrl.editMode\"><table><tr><td class=></td><td class=\"minutes\" ng-repeat=\"segment in [0,1,2,3,4,5,6,7,8,9,10,11]\">{{ segment * 5 }}</td></tr><tr ng-repeat=\"hourSegments in $ctrl.editMatrix track by $index\"><td class=\"hours\">{{ $index }}</td><td class=\"cell\" ng-repeat=\"segment in hourSegments track by $index\"><input type=\"checkbox\" ng-model=\"segment.value\" ng-true-value=\"1\" ng-false-value=\"0\"></td><td><button ng-click=\"$ctrl.checkAll($index)\">1</button><button ng-click=\"$ctrl.uncheckAll($index)\">0</button><button ng-click=\"$ctrl.checkHalf($index)\">½</button><button ng-click=\"$ctrl.checkFourth($index)\">¼</button><button ng-click=\"$ctrl.checkSixth($index)\">⅙</button><button ng-click=\"$ctrl.checkTwelveth($index)\">¹⁄₁₂</button><button ng-click=\"$ctrl.invertAll($index)\">∨</button></td></tr></table><button ng-click=\"$ctrl.saveSchedule()\">Save Schedule</button></div></div>`,controller: 'PlugScheduleController'});</script><div ng-app=\"plugSchedulerApp\" id=\"main_container\"><div ng-controller=\"PlugScheduleController\"><plug-schedule-widget plug-id=\"1\"></plug-schedule-widget><plug-schedule-widget plug-id=\"2\"></plug-schedule-widget><plug-schedule-widget plug-id=\"3\"></plug-schedule-widget><plug-schedule-widget plug-id=\"4\"></plug-schedule-widget><plug-schedule-widget plug-id=\"5\"></plug-schedule-widget><plug-schedule-widget plug-id=\"6\"></plug-schedule-widget><plug-schedule-widget plug-id=\"7\"></plug-schedule-widget><plug-schedule-widget plug-id=\"8\"></plug-schedule-widget></div><!--<div ng-controller=\"ApiHostController\"><h3>Change Host<input type=\"text\" ng-model=\"data.api_host\" value=\"{{data.api_host}}\" style=\"margin: 10px;padding: 3px; font-size: 14pt; color: #333340; border-radius: 6px;\"></h3></div>--></div><style>* {font-family: Calibri, Candara, Segoe, Segoe UI, Optima, Arial, sans-serif;padding: 0px;border-spacing: 0px;border: transparent;text-align: center;color: #aaa;font-weight: normal;font-size: 20pt;}body {margin: auto;background: #333340;}button {background: #696983;border-radius: 6px;box-shadow: 1px 1px 3px rgba(0,0,0,0.6);color: eee;font-size: 0.8em;margin-left: 4px;padding: 14px;vertical-align: top;}button.modify {margin: 4px;}button.modifiers {width: 40px;}button:hover {background: #9f9fc4;box-shadow: inset 1px 1px 3px rgba(0,0,0,0.6);}.hour-cell {display: inline-block;width: 25px;height: 50px;margin-top: 4px;}.minutes, .hours {font-size: 0.6em;color: rgba(255, 255, 255, .5);padding: 6px;}table tr td {padding: 3px;}tr:nth-child(2n) {box-shadow: inset 1px 1px 4px 1px rgba(0,0,0,0.54);background: rgba(0, 0, 0, 0.07);}tr td.cell {border-left: 1px solid rgba(61, 61, 78, .61);}div#main_container {margin: auto;}.off {background-color: #eee;}.on {background-color: #8e8;}.partial {background-color: #bdc;}table {margin: auto;}</style></body></html>";
|
||
|
||
|
||
// PREFERENCES
|
||
Preferences preferences;
|
||
#define RW_MODE false
|
||
#define RO_MODE true
|
||
|
||
// WIFI
|
||
const char* ssid = "/tmp/lab";
|
||
const char* password = "bitte2cucung";
|
||
// const char* ssid = "Wokwi-GUEST";
|
||
// const char* password = "";
|
||
const uint8_t wifi_loop_max = 10;
|
||
|
||
// NTP
|
||
bool sntp_initialized = false;
|
||
const char* ntpServer1 = "pool.ntp.org";
|
||
const char* ntpServer2 = "time.nist.gov";
|
||
const long gmtOffset_sec = 2 * 3600; // GMT + 2
|
||
const int daylightOffset_sec = 0;
|
||
|
||
// TIMER
|
||
hw_timer_t*timer_main = NULL;
|
||
uint32_t timer_interval = 3000000;
|
||
uint16_t timer_interval_in_secs = timer_interval / 1000000;
|
||
;
|
||
|
||
// SCHEDULER
|
||
bool brun_scheduler = true;
|
||
uint8_t current_hour = HOUR_DEFAULT;
|
||
uint8_t current_minute = MINUTE_DEFAULT;
|
||
uint8_t current_second = 0;
|
||
uint32_t current_ts = 0;
|
||
uint32_t next_event_ts = 0;
|
||
int scheduler_1[24] ; // = {A60,A60,A60,A60,A60,A60,A60,A60,A60,A60,A60,A60,A60,A60,A60,A60,A60,A60,A60,A60,A60,A60,A60,A60};
|
||
int scheduler_2[24] ; // = {A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00};
|
||
int scheduler_3[24] ; // = {A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00};
|
||
int scheduler_4[24] ; // = {A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00};
|
||
int scheduler_5[24] ; // = {A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00};
|
||
int scheduler_6[24] ; // = {A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00};
|
||
int scheduler_7[24] ; // = {A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00};
|
||
int scheduler_8[24] ; // = {A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00,A00};
|
||
int* scheduler_list[] = {
|
||
scheduler_1,
|
||
scheduler_2,
|
||
scheduler_3,
|
||
scheduler_4,
|
||
scheduler_5,
|
||
scheduler_6,
|
||
scheduler_7,
|
||
scheduler_8,
|
||
};
|
||
|
||
// PINS
|
||
unsigned int PIN_1 = 12;
|
||
unsigned int PIN_2 = 14;
|
||
unsigned int PIN_3 = 27;
|
||
unsigned int PIN_4 = 26;
|
||
unsigned int PIN_5 = 20;
|
||
unsigned int PIN_6 = 33;
|
||
unsigned int PIN_7 = 32;
|
||
unsigned int PIN_8 = 35;
|
||
unsigned int pin_list[8] = {
|
||
PIN_1,
|
||
PIN_2,
|
||
PIN_3,
|
||
PIN_4,
|
||
PIN_5,
|
||
PIN_6,
|
||
PIN_7,
|
||
PIN_8
|
||
};
|
||
|
||
// HTTP
|
||
WiFiClient client;
|
||
WiFiServer http_server(3000);
|
||
String request;
|
||
|
||
|
||
|
||
// --------------------------------------------
|
||
// Local functions
|
||
// --------------------------------------------
|
||
|
||
|
||
// Time helper
|
||
uint32_t get_timestamp( uint8_t hour, uint8_t minute, uint8_t second){
|
||
return ( 3600 * hour + 60 * minute + second) % 86400;
|
||
}
|
||
|
||
bool event_keep_waiting( uint32_t current_ts, uint32_t event_ts ){
|
||
|
||
// basic case
|
||
// ts: 11h 41m 11s
|
||
// ev: 11h 44m 0s
|
||
// ts < ev => TRUE
|
||
if ( current_ts < event_ts ){
|
||
return true;
|
||
}
|
||
// if time looped at midnight
|
||
// ts: 23h 57m 21s
|
||
// ev: 0h 1m 0s
|
||
// ts > ev => TRUE (for high to very low values )
|
||
if( (current_ts - event_ts) > 600 && event_ts < 300 ) {
|
||
return true;
|
||
}
|
||
// ts: 11h 44m 11s
|
||
// ev: 11h 44m 0s
|
||
// ts > ev => FALSE
|
||
return false;
|
||
}
|
||
|
||
|
||
// NTP Callback
|
||
void timeavailable(struct timeval *t)
|
||
{
|
||
Serial.println("NTP::Got time adjustment from NTP!");
|
||
sntp_initialized = true;
|
||
return;
|
||
}
|
||
|
||
// TIMER Callback
|
||
void IRAM_ATTR onTimer(){
|
||
brun_scheduler = true;
|
||
}
|
||
|
||
|
||
void run_scheduler(){
|
||
// Serial.println("onTimer::run");
|
||
// Get the current time via NTP, or downgrade
|
||
if ( sntp_initialized ){
|
||
struct tm timeinfo;
|
||
time_t now;
|
||
time(&now);
|
||
localtime_r(&now, &timeinfo);
|
||
current_hour = timeinfo.tm_hour;
|
||
current_minute = timeinfo.tm_min;
|
||
current_second = timeinfo.tm_sec;
|
||
|
||
// If no NTP clock
|
||
}else{
|
||
|
||
// Serial.println("onTimer::NO NTP");
|
||
current_second += timer_interval_in_secs;
|
||
if(current_second >= 60) {
|
||
current_second = 0;
|
||
current_minute += 1;
|
||
if(current_minute >= 60) {
|
||
current_minute = 0;
|
||
current_hour += 1;
|
||
if(current_hour >= 24) {
|
||
current_hour = 0;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// If not expected to run exit
|
||
current_ts = get_timestamp( current_hour, current_minute, current_second );
|
||
// Serial.printf("onTimer::check event %d %d\n", current_ts, next_event_ts);
|
||
if( event_keep_waiting( current_ts, next_event_ts ) ){
|
||
return;
|
||
}
|
||
|
||
// Set the next target
|
||
next_event_ts = get_timestamp( current_hour, current_minute + EVENT_INC_MINUTE, current_second );
|
||
Serial.println("Reconfigure the Relays!");
|
||
|
||
// Run the relays reconfiguration
|
||
for ( int i = 0; i < 8; i++ ) {
|
||
// Get a pointer to the current array
|
||
int* scheduler = scheduler_list[i];
|
||
unsigned int pin = pin_list[i];
|
||
// Set the expected status
|
||
uint8_t minutes_by_5 = (current_minute / 5);
|
||
int hourly_12_values = scheduler[current_hour];
|
||
// Serial.printf("Check hour(%d) >> minutes(%d x 5)\n", hourly_12_values, minutes_by_5);
|
||
|
||
char buffer[40];
|
||
|
||
if (( hourly_12_values >> minutes_by_5 ) & 1) {
|
||
digitalWrite(pin, HIGH);
|
||
sprintf (buffer, "Pin %d is up ", pin);
|
||
} else {
|
||
digitalWrite(pin, LOW);
|
||
sprintf (buffer, "Pin %d is down ", pin);
|
||
}
|
||
Serial.println(buffer); // Get the expected status
|
||
}
|
||
Serial.println("Reconfiguration over");
|
||
return;
|
||
}
|
||
|
||
|
||
// HTTP
|
||
|
||
const char* getPreferenceName( int plug_id){
|
||
switch (plug_id) {
|
||
case 0:
|
||
return RELAY_1_SCHEDULE;
|
||
break;
|
||
case 1:
|
||
return RELAY_2_SCHEDULE;
|
||
break;
|
||
case 2:
|
||
return RELAY_3_SCHEDULE;
|
||
break;
|
||
case 3:
|
||
return RELAY_4_SCHEDULE;
|
||
break;
|
||
case 4:
|
||
return RELAY_5_SCHEDULE;
|
||
break;
|
||
case 5:
|
||
return RELAY_6_SCHEDULE;
|
||
break;
|
||
case 6:
|
||
return RELAY_7_SCHEDULE;
|
||
break;
|
||
case 7:
|
||
return RELAY_8_SCHEDULE;
|
||
break;
|
||
}
|
||
}
|
||
|
||
void saveSchedule( int plug_id, unsigned int data[24]){
|
||
const char* preference_name = getPreferenceName( plug_id );
|
||
Serial.print("saving to ");
|
||
Serial.println(preference_name);
|
||
preferences.putBytes(preference_name, data, sizeof(data));
|
||
|
||
}
|
||
|
||
void sendSchedule(WiFiClient &client, int plug_id) {
|
||
int buf[24];
|
||
const char* preference_name = getPreferenceName( plug_id );
|
||
preferences.getBytes(preference_name, buf, preferences.getBytesLength(preference_name));
|
||
client.write((const uint8_t*)buf, 24 * sizeof(int));
|
||
}
|
||
|
||
// --------------------------------------------
|
||
// ARDUINO Functions
|
||
// --------------------------------------------
|
||
|
||
void setup(){
|
||
|
||
// HARDWARE
|
||
Serial.begin(115200);
|
||
delay(1000);
|
||
Serial.println("Starting.");
|
||
pinMode(PIN_1, OUTPUT);
|
||
pinMode(PIN_2, OUTPUT);
|
||
// PREFERENCES
|
||
Serial.println("Setup::PREFERENCES");
|
||
preferences.begin(PREF_NAMESPACE, RW_MODE);
|
||
preferences.clear();
|
||
|
||
bool pref_init = preferences.isKey("test");
|
||
if (pref_init == false) {
|
||
Serial.println("preferences not exist");
|
||
preferences.putBool("test", true);
|
||
/*
|
||
saveSchedule(1,scheduler_default_deactivate);
|
||
saveSchedule(2,scheduler_default_deactivate);
|
||
saveSchedule(3,scheduler_default_deactivate);
|
||
saveSchedule(4,scheduler_default_deactivate);
|
||
saveSchedule(5,scheduler_default_deactivate);
|
||
saveSchedule(6,scheduler_default_deactivate);
|
||
saveSchedule(7,scheduler_default_deactivate);
|
||
saveSchedule(8,scheduler_default_deactivate);
|
||
*/
|
||
}
|
||
/*
|
||
preferences.getBytes(RELAY_1_SCHEDULE, scheduler_1, preferences.getBytesLength(RELAY_1_SCHEDULE));
|
||
preferences.getBytes(RELAY_2_SCHEDULE, scheduler_2, preferences.getBytesLength(RELAY_2_SCHEDULE));
|
||
preferences.getBytes(RELAY_3_SCHEDULE, scheduler_2, preferences.getBytesLength(RELAY_3_SCHEDULE));
|
||
preferences.getBytes(RELAY_4_SCHEDULE, scheduler_2, preferences.getBytesLength(RELAY_4_SCHEDULE));
|
||
preferences.getBytes(RELAY_5_SCHEDULE, scheduler_2, preferences.getBytesLength(RELAY_5_SCHEDULE));
|
||
preferences.getBytes(RELAY_6_SCHEDULE, scheduler_2, preferences.getBytesLength(RELAY_6_SCHEDULE));
|
||
preferences.getBytes(RELAY_7_SCHEDULE, scheduler_2, preferences.getBytesLength(RELAY_7_SCHEDULE));
|
||
preferences.getBytes(RELAY_8_SCHEDULE, scheduler_2, preferences.getBytesLength(RELAY_8_SCHEDULE));
|
||
*/
|
||
preferences.end();
|
||
Serial.println("Setup::PREFERENCES::end");
|
||
|
||
// WIFI
|
||
Serial.println("Setup::WIFI");
|
||
Serial.printf("Connecting to %s ", ssid);
|
||
WiFi.begin(ssid, password);
|
||
uint8_t wifi_loop_count = 0;
|
||
while (WiFi.status() != WL_CONNECTED or wifi_loop_count < wifi_loop_max ) {
|
||
delay(1000);
|
||
wifi_loop_count++;
|
||
Serial.print(".");
|
||
}
|
||
|
||
// TIMER
|
||
Serial.println("Setup::Timer");
|
||
timer_main = timerBegin(0, 80, true);
|
||
timerAttachInterrupt(timer_main, &onTimer, true);
|
||
timerAlarmWrite(timer_main, timer_interval, true);
|
||
timerAlarmEnable(timer_main);
|
||
|
||
// NTP
|
||
Serial.println("Setup::NTP");
|
||
sntp_set_time_sync_notification_cb(timeavailable);
|
||
configTime(gmtOffset_sec, daylightOffset_sec, ntpServer1, ntpServer2);
|
||
delay(5000);
|
||
|
||
// SCHEDULER
|
||
Serial.println("Setup::SCHEDULER");
|
||
next_event_ts = get_timestamp( HOUR_DEFAULT, MINUTE_DEFAULT, 10 );
|
||
|
||
|
||
// HTTP
|
||
Serial.println("Setup::HTTP");
|
||
http_server.begin();
|
||
Serial.print("Connect to IP Address: ");
|
||
Serial.print("http://");
|
||
Serial.println(WiFi.localIP());
|
||
|
||
// Todo
|
||
|
||
}
|
||
|
||
|
||
|
||
void loop(){
|
||
|
||
if( brun_scheduler == true ){
|
||
brun_scheduler = false;
|
||
run_scheduler();
|
||
}
|
||
|
||
client = http_server.available();
|
||
if (!client) {
|
||
// Serial.println("Server not available... skip...");
|
||
return;
|
||
}
|
||
|
||
String request = client.readStringUntil('\r');
|
||
|
||
Serial.print("request: ");
|
||
Serial.println(request);
|
||
|
||
// GET request
|
||
if (request.indexOf("GET /api/schedule/") >= 0) {
|
||
int startIdIndex = 18;
|
||
int endIdIndex = 19;
|
||
|
||
String plug_idStr = request.substring(startIdIndex, endIdIndex);
|
||
int plug_id = plug_idStr.toInt() - 1; // Adjust for 0 index
|
||
Serial.print("plug_id " );
|
||
Serial.println(plug_id);
|
||
if (plug_id >= 0 && plug_id < 8) {
|
||
client.println("HTTP/1.1 200 OK");
|
||
client.println("Content-Type: text/html");
|
||
client.println("Connection: close");
|
||
client.println();
|
||
sendSchedule(client, plug_id);
|
||
} else {
|
||
client.println("HTTP/1.1 404 Not Found");
|
||
client.println("Connection: close");
|
||
client.println();
|
||
}
|
||
// GET homepage
|
||
} else if (request.indexOf("GET /") >= 0) {
|
||
client.println("HTTP/1.1 200 OK");
|
||
client.println("Content-Type: text/html");
|
||
client.println("Connection: close");
|
||
client.println();
|
||
client.println(html_app);
|
||
} else {
|
||
|
||
// POST request
|
||
int slashIndex = request.indexOf("POST /api/schedule/");
|
||
if (slashIndex != -1) {
|
||
Serial.print("slashIndex: ");
|
||
Serial.println(slashIndex);
|
||
int nextSlashIndex = slashIndex + 19;
|
||
|
||
// Extract the plug ID
|
||
String plug_idStr = request.substring(nextSlashIndex, nextSlashIndex + 1);
|
||
Serial.print("plug_idStr ");
|
||
Serial.println(plug_idStr);
|
||
int plug_id = plug_idStr.toInt() - 1;
|
||
// Force a new line
|
||
client.readStringUntil('\n');
|
||
// Read the next line which should have the POST body/content
|
||
String preBody ;
|
||
while ( preBody = client.readStringUntil('\n') ){
|
||
if( preBody.isEmpty() ){
|
||
break;
|
||
}
|
||
}
|
||
Serial.println("Done reading. Going for binary.");
|
||
|
||
char post_body[24];
|
||
client.readBytes(post_body, 24);
|
||
Serial.print("Read post_body: ");
|
||
Serial.println(post_body);
|
||
|
||
// Update the schedule for the specified plug
|
||
if (plug_id >= 0 && plug_id < 8) {
|
||
|
||
unsigned int byte_value[24];
|
||
for (int i=0; i < 24; i++) {
|
||
byte_value[i] = (int) post_body[i];
|
||
}
|
||
|
||
saveSchedule(plug_id, byte_value );
|
||
Serial.println("Schedule updated for plug " + plug_idStr);
|
||
} else {
|
||
Serial.println("Invalid plug ID");
|
||
}
|
||
client.println("HTTP/1.1 200 OK");
|
||
client.println("Content-Type: text/plain");
|
||
client.println("Connection: close");
|
||
client.println();
|
||
}
|
||
}
|
||
|
||
client.stop();
|
||
|
||
|
||
}
|