diff --git a/Arduino/CanGrow/include/CanGrow.h b/Arduino/CanGrow/include/CanGrow.h index b7384a3..8dacb05 100644 --- a/Arduino/CanGrow/include/CanGrow.h +++ b/Arduino/CanGrow/include/CanGrow.h @@ -179,7 +179,7 @@ struct Config_System_Output { /* * Config System Output * - * - output_type: output type like GPIO, I2C, URL + * - type: output type like GPIO, I2C, URL * 1 - GPIO * 2 - I2C * 3 - Web @@ -215,6 +215,36 @@ struct Config_System_Output { char webcall_path_off[Max_Outputs][32]; }; +struct Config_System_Sensor { + /* + * Config System Sensor + * + * - Sensor Name + * - Sensors can offer following types + * - temperature + * - humidity + * - moisture + * - raw + * + * + * - type: sensor type like I2C, OneWire, ... + * 1 - builtin ADC + * 2 - I2C + * 3 - Webcall + * + * What are sensors? + * - Analog builtin + * - I2C ADC + * - I2C Soil Moisture + * - I2C often multisensor offering mutliple values for temp, humidity, light , whatever + * - + */ + + byte type[Max_Outputs]; + byte device[Max_Outputs]; + char name[Max_Outputs][32]; +}; + /* main System struct */ struct Config_System { byte ntpOffset; @@ -225,6 +255,7 @@ struct Config_System { bool httpLogSerial; unsigned short schedulerInterval = 1000; Config_System_Output output; + Config_System_Sensor sensor; }; diff --git a/Arduino/CanGrow/include/CanGrow_Webserver.h b/Arduino/CanGrow/include/CanGrow_Webserver.h index 41d8af4..329299e 100644 --- a/Arduino/CanGrow/include/CanGrow_Webserver.h +++ b/Arduino/CanGrow/include/CanGrow_Webserver.h @@ -110,9 +110,17 @@ void Webserver_Init() { webserver.on("/system/output/add", HTTP_GET, WebPage_system_output_add); webserver.on("/system/output/add", HTTP_POST, WebPage_system_output_add); - requestLogger.setOutput(Serial); + webserver.on("/system/sensor/", HTTP_GET, WebPage_system_sensor); + webserver.on("/system/sensor/", HTTP_POST, WebPage_system_sensor); + + webserver.on("/system/sensor/add", HTTP_GET, WebPage_system_sensor_add); + webserver.on("/system/sensor/add", HTTP_POST, WebPage_system_sensor_add); + + + // this activates the middleware if(config.system.httpLogSerial == true) { + requestLogger.setOutput(Serial); Serial.println(":: [Webserver] serial logging: enabled"); webserver.addMiddleware(&requestLogger); } else { diff --git a/Arduino/CanGrow/include/Webserver/Footer.h b/Arduino/CanGrow/include/Webserver/Footer.h index d304dd2..2899bf9 100644 --- a/Arduino/CanGrow/include/Webserver/Footer.h +++ b/Arduino/CanGrow/include/Webserver/Footer.h @@ -27,5 +27,4 @@ * */ -const char* Footer_HTML PROGMEM = R"( -)"; +const char* Footer_HTML PROGMEM = R"()"; diff --git a/Arduino/CanGrow/include/Webserver/Page_system.h b/Arduino/CanGrow/include/Webserver/Page_system.h index 8fbae94..f5803c8 100644 --- a/Arduino/CanGrow/include/Webserver/Page_system.h +++ b/Arduino/CanGrow/include/Webserver/Page_system.h @@ -43,7 +43,7 @@ * variable, so the template processor can read it. */ byte tmpParam_editOutputId = 255; - +byte tmpParam_editSensorId = 255; @@ -52,6 +52,7 @@ byte tmpParam_editOutputId = 255; bool Test_WebPage_system_SUBNAV(const String& var) { if( (var == "SUBNAV") || + (var == "ACTIVE_SUBNAV_SENSOR") || (var == "ACTIVE_SUBNAV_OUTPUT") || (var == "ACTIVE_SUBNAV_UPDATE") || (var == "ACTIVE_SUBNAV_RESTART") || @@ -75,24 +76,30 @@ String Proc_WebPage_system_SUBNAV(const String& var, byte activeSubnav = 0) { String activeSubnav_ClassName = "activeNav"; if(var == "SUBNAV") { return String(Page_system_HTML_SUBNAV); - } else if((var == "ACTIVE_SUBNAV_OUTPUT") && (activeSubnav == 1)) { + } else if((var == "ACTIVE_SUBNAV_SENSOR") && (activeSubnav == 1)) { return activeSubnav_ClassName; - } else if((var == "ACTIVE_SUBNAV_UPDATE") && (activeSubnav == 2)) { + } else if((var == "ACTIVE_SUBNAV_OUTPUT") && (activeSubnav == 2)) { return activeSubnav_ClassName; - } else if((var == "ACTIVE_SUBNAV_RESTART") && (activeSubnav == 3)) { + } else if((var == "ACTIVE_SUBNAV_UPDATE") && (activeSubnav == 3)) { return activeSubnav_ClassName; - } else if((var == "ACTIVE_SUBNAV_WIPE") && (activeSubnav == 4)) { + } else if((var == "ACTIVE_SUBNAV_RESTART") && (activeSubnav == 4)) { + return activeSubnav_ClassName; + } else if((var == "ACTIVE_SUBNAV_WIPE") && (activeSubnav == 5)) { return activeSubnav_ClassName; } else { return String(); } } -/* +/******************************************************************************* * Main system page */ // https://techtutorialsx.com/2018/07/23/esp32-arduino-http-server-template-processing-with-multiple-placeholders/ String Proc_WebPage_system(const String& var) { + #ifndef DEBUG + Serial.print("DB [Webserver:system(Proc)] var: "); + Serial.println(var); + #endif if(TestHeaderFooter(var)) { return AddHeaderFooter(var, 2); } else if(Test_WebPage_system_SUBNAV(var)) { @@ -150,14 +157,14 @@ void WebPage_system(AsyncWebServerRequest *request) { } -/* +/******************************************************************************* * Subpage restart */ String Proc_WebPage_system_restart(const String& var) { if(TestHeaderFooter(var)) { return AddHeaderFooter(var, 2); } else if(Test_WebPage_system_SUBNAV(var)) { - return Proc_WebPage_system_SUBNAV(var, 3); + return Proc_WebPage_system_SUBNAV(var, 4); } else if(var == "RESTART_MSG") { return String(Page_system_restart_HTML_RESTART_MSG); } else { @@ -194,7 +201,7 @@ void WebPage_system_restart(AsyncWebServerRequest *request) { -/* +/******************************************************************************* * Subpage update */ @@ -231,7 +238,7 @@ String Proc_WebPage_system_update(const String& var) { if(TestHeaderFooter(var)) { return AddHeaderFooter(var, 2); } else if(Test_WebPage_system_SUBNAV(var)) { - return Proc_WebPage_system_SUBNAV(var, 2); + return Proc_WebPage_system_SUBNAV(var, 3); } else { return String(); } @@ -264,14 +271,14 @@ void WebPage_system_update(AsyncWebServerRequest *request) { } -/* +/******************************************************************************* * Subpage wipe */ String Proc_WebPage_system_wipe(const String& var) { if(TestHeaderFooter(var)) { return AddHeaderFooter(var, 2); } else if(Test_WebPage_system_SUBNAV(var)) { - return Proc_WebPage_system_SUBNAV(var, 4); + return Proc_WebPage_system_SUBNAV(var, 5); } else if(var == "WIPE_MSG") { return String(Page_system_wipe_HTML_WIPE_MSG); } else { @@ -305,7 +312,7 @@ void WebPage_system_wipe(AsyncWebServerRequest *request) { } -/* +/******************************************************************************* * Subpage output */ String Proc_WebPage_system_output(const String& var) { @@ -316,7 +323,7 @@ String Proc_WebPage_system_output(const String& var) { if(TestHeaderFooter(var)) { return AddHeaderFooter(var, 2); } else if(Test_WebPage_system_SUBNAV(var)) { - return Proc_WebPage_system_SUBNAV(var, 1); + return Proc_WebPage_system_SUBNAV(var, 2); } else if(var == "OUTPUT_TR_TD") { // build table body // i dont know a better way at the moment. if you do, please tell me! @@ -418,7 +425,7 @@ void WebPage_system_output(AsyncWebServerRequest *request) { } -/* +/******************************************************************************* * Subpage output add */ @@ -466,7 +473,7 @@ String Proc_WebPage_system_output_addCommon(const String& var) { if(TestHeaderFooter(var)) { return AddHeaderFooter(var, 2); } else if(Test_WebPage_system_SUBNAV(var)) { - return Proc_WebPage_system_SUBNAV(var, 1); + return Proc_WebPage_system_SUBNAV(var, 2); } else if(var == "OUTPUT_ID") { // we check which id is free. A free ID as type == 0 return String(Give_Free_OutputId()); @@ -497,7 +504,7 @@ String Proc_WebPage_system_output_add(const String& var) { if(TestHeaderFooter(var)) { return AddHeaderFooter(var, 2); } else if(Test_WebPage_system_SUBNAV(var)) { - return Proc_WebPage_system_SUBNAV(var, 1); + return Proc_WebPage_system_SUBNAV(var, 2); } else if(var == "ACTION") { return String("➕ Add"); @@ -545,7 +552,7 @@ String Proc_WebPage_system_output_addEdit(const String& var) { if(TestHeaderFooter(var)) { return AddHeaderFooter(var, 2); } else if(Test_WebPage_system_SUBNAV(var)) { - return Proc_WebPage_system_SUBNAV(var, 1); + return Proc_WebPage_system_SUBNAV(var, 2); } else if(var == "ACTION") { return String("✏️ Edit"); @@ -734,3 +741,432 @@ void WebPage_system_output_add(AsyncWebServerRequest *request) { } } } + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +/******************************************************************************* + * Subpage sensor + */ + +String Proc_WebPage_system_sensor(const String& var) { + #ifndef DEBUG + Serial.print("DB [Webserver:system:sensor(Proc)] var: "); + Serial.println(var); + #endif + if(TestHeaderFooter(var)) { + return AddHeaderFooter(var, 2); + } else if(Test_WebPage_system_SUBNAV(var)) { + return Proc_WebPage_system_SUBNAV(var, 1); + } else if(var == "OUTPUT_TR_TD") { + // build table body + // i dont know a better way at the moment. if you do, please tell me! + String output_tr_td; + for(byte i=0; i < Max_Outputs; i++) { + if(config.system.output.type[i] > 0) { + #ifndef DEBUG + Serial.printf("DB [Webserver:system:output(Proc)] OutputID %d Type %d\n", i, config.system.output.type[i]); + #endif + output_tr_td += ""; + output_tr_td += i; + output_tr_td += ""; + output_tr_td += config.system.output.name[i]; + output_tr_td += ""; + output_tr_td += Output_Type_descr[config.system.output.type[i]]; + output_tr_td += ""; + output_tr_td += Output_Device_descr[config.system.output.device[i]]; + output_tr_td += ""; + output_tr_td += config.system.output.enabled[i]; + output_tr_td += ""; + + // edit button + output_tr_td += "
"; + output_tr_td += ""; + output_tr_td += "
"; + + + // delete button + output_tr_td += "
"; + output_tr_td += ""; + output_tr_td += "
"; + + output_tr_td += ""; + } + } + + return output_tr_td; + } else{ + return String(); + } +} + +String Proc_WebPage_system_sensor_POST(const String& var) { + if(var == "SAVE_MSG") { + return String(Common_HTML_SAVE_MSG); + } else { + return Proc_WebPage_system_output(var); + } +} + +void WebPage_system_sensor(AsyncWebServerRequest *request) { + if(request->method() == HTTP_POST) { + if(request->hasParam("delete_output", true)) { + byte outputId; + + const AsyncWebParameter* p_delete_output = request->getParam("delete_output", true); + Serial.printf(":: [Webserver:system:output] POST[%s]: %s\n", p_delete_output->name().c_str(), p_delete_output->value().c_str()); + + outputId = p_delete_output->value().toInt(); + + Serial.printf(":: [Webserver:system:output] Deleting output: %d\n", outputId); + + // we ensure that every field is empty + config.system.output.type[outputId] = 0; + config.system.output.device[outputId] = 0; + // set every field of char array to 0x00 with memset + memset(config.system.output.name[outputId], '\0', sizeof config.system.output.name[outputId]); + config.system.output.enabled[outputId] = 0; + config.system.output.gpio[outputId] = 0; + config.system.output.gpio_pwm[outputId] = 0; + config.system.output.gpio_invert[outputId] = 0; + memset(config.system.output.i2c[outputId], '\0', sizeof config.system.output.i2c[outputId]); + memset(config.system.output.webcall_host[outputId], '\0', sizeof config.system.output.webcall_host[outputId]); + memset(config.system.output.webcall_path_on[outputId], '\0', sizeof config.system.output.webcall_path_on[outputId]); + memset(config.system.output.webcall_path_off[outputId], '\0', sizeof config.system.output.webcall_path_off[outputId]); + + SaveConfig(); + } + + + request->send_P(200, "text/html", Page_system_sensor_HTML, Proc_WebPage_system_sensor_POST); + Serial.println(":: [Webserver:system:output] [POST] hello"); + + + } else { + if(request->hasParam("success")) { + // when GET param success is present, we use the _POST processor for the save message + request->send_P(200, "text/html", Page_system_sensor_HTML, Proc_WebPage_system_sensor_POST); + } else { + request->send_P(200, "text/html", Page_system_sensor_HTML, Proc_WebPage_system_sensor); + } + } + +} + +/******************************************************************************* + * Subpage sensor add + */ + +/* returns select