system/sensor stuff wip

This commit is contained in:
Marcus 2024-11-12 22:25:02 +01:00
parent 92724fa1f4
commit 0571acc350
5 changed files with 613 additions and 27 deletions

View file

@ -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;
};

View file

@ -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 {

View file

@ -27,5 +27,4 @@
*
*/
const char* Footer_HTML PROGMEM = R"(<div class='footer'><span>Build: %CGBUILD%</span></div>
</div></body></html>)";
const char* Footer_HTML PROGMEM = R"(<div class='footer'><span>Build: %CGBUILD%</span></div></div></body></html>)";

View file

@ -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("&#10133; 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("&#x270F;&#xFE0F; 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 += "<tr><td>";
output_tr_td += i;
output_tr_td += "</td><td>";
output_tr_td += config.system.output.name[i];
output_tr_td += "</td><td>";
output_tr_td += Output_Type_descr[config.system.output.type[i]];
output_tr_td += "</td><td>";
output_tr_td += Output_Device_descr[config.system.output.device[i]];
output_tr_td += "</td><td>";
output_tr_td += config.system.output.enabled[i];
output_tr_td += "</td><td>";
// edit button
output_tr_td += "<form class='linkForm' action='/system/output/add' method='get'>";
output_tr_td += "<input type='hidden' name='edit' value='";
output_tr_td += i;
output_tr_td += "'>";
output_tr_td += "<input type='submit' value='&#x270F;&#xFE0F;'></form> ";
// delete button
output_tr_td += "<form class='linkForm' action='/system/output/' method='post'>";
output_tr_td += "<input type='hidden' name='delete_output' value='";
output_tr_td += i;
output_tr_td += "'>";
output_tr_td += "<input type='submit' value='&#x274C;' onclick=\"return confirmDelete('";
output_tr_td += config.system.output.name[i];;
output_tr_td += "')\"></form>";
output_tr_td += "</td></tr>";
}
}
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 <option> list of available output types */
String Html_SelOpt_type_WebPage_system_sensor_add(byte selectId = 255) {
String outputType_html;
// go through all available Output Devices, skip 0 because it means unconfigured
for(byte i = 1; i < Output_Type_total; i++) {
outputType_html += "<option value='";
outputType_html += i;
outputType_html += "'";
if(i == selectId) {
outputType_html += " selected";
}
outputType_html += ">";
outputType_html += Output_Type_descr[i];
outputType_html += "</option>";
}
return outputType_html;
}
String Html_SelOpt_device_WebPage_system_sensor_add(byte selectId = 255) {
String outputDevice_html;
// go through all available Output Devices, skip 0 because it means unconfigured
for(byte i = 1; i < Output_Device_total; i++) {
outputDevice_html += "<option value='";
outputDevice_html += i;
outputDevice_html += "'";
if(i == selectId) {
outputDevice_html += " selected";
}
outputDevice_html += ">";
outputDevice_html += Output_Device_descr[i];
outputDevice_html += "</option>";
}
return outputDevice_html;
}
String Proc_WebPage_system_sensor_add(const String& var) {
#ifndef DEBUG
Serial.print("DB [Webserver:system:output:add(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 == "ACTION") {
return String("&#10133; Add");
} else if(var == "OUTPUT_ID") {
// we check which id is free. A free ID as type == 0
return String(Give_Free_OutputId());
} else if(var == "OUTPUT_TYPE") {
return Html_SelOpt_type_WebPage_system_output_add();
} else if(var == "OUTPUT_DEVICE") {
return Html_SelOpt_device_WebPage_system_output_add();
} else if(var == "OUTPUT_ENABLED") {
return Html_SelectOpt_bool();
} else if(var == "GPIO_INDEX") {
return Html_SelectOpt_GPIOindex();
} else if(var == "GPIO_PWM") {
return Html_SelectOpt_bool();
} else if(var == "GPIO_INVERT") {
return Html_SelectOpt_bool();
} else {
return String();
}
}
String Proc_WebPage_system_sensor_addEdit(const String& var) {
#ifndef DEBUG
Serial.print("DB [Webserver:system:output:addEdit(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 == "ACTION") {
return String("&#x270F;&#xFE0F; Edit");
} else if(var == "OUTPUT_ID") {
// return the outputId we got from GET .../add?edit=ID
// dirty workaround to put this in a global variable
return String(tmpParam_editOutputId);
} else if(var == "OUTPUT_TYPE") {
return Html_SelOpt_type_WebPage_system_output_add(config.system.output.type[tmpParam_editOutputId]);
} else if(var == "OUTPUT_DEVICE") {
return Html_SelOpt_device_WebPage_system_output_add(config.system.output.device[tmpParam_editOutputId]);
} else if(var == "OUTPUT_NAME") {
// "escape" % character, because it would break the template processor.
// tasmote webcall for example has percentage char in its path
String outputName = config.system.output.name[tmpParam_editOutputId];;
outputName.replace("%", "&#37;");
return outputName;
} else if(var == "OUTPUT_ENABLED") {
return Html_SelectOpt_bool(config.system.output.enabled[tmpParam_editOutputId]);
} else if(var == "GPIO_INDEX") {
return Html_SelectOpt_GPIOindex(config.system.output.gpio[tmpParam_editOutputId]);
} else if(var == "GPIO_PWM") {
return Html_SelectOpt_bool(config.system.output.gpio_pwm[tmpParam_editOutputId]);
} else if(var == "GPIO_INVERT") {
return Html_SelectOpt_bool(config.system.output.gpio_invert[tmpParam_editOutputId]);
} else if(var == "I2C") {
return String(config.system.output.i2c[tmpParam_editOutputId]);
} else if(var == "WEBCALL_HOST") {
return String(config.system.output.webcall_host[tmpParam_editOutputId]);
} else if(var == "WEBCALL_PATH_ON") {
String webcallPathOn = config.system.output.webcall_path_on[tmpParam_editOutputId];
webcallPathOn.replace("%", "&#37;");
return webcallPathOn;
} else if(var == "WEBCALL_PATH_OFF") {
String webcallPathOff = config.system.output.webcall_path_off[tmpParam_editOutputId];
webcallPathOff.replace("%", "&#37;");
return webcallPathOff;
} else if(
((var == "CLASS_TYPE_1") && (config.system.output.type[tmpParam_editOutputId] == 1)) ||
((var == "CLASS_TYPE_2") && (config.system.output.type[tmpParam_editOutputId] == 2)) ||
((var == "CLASS_TYPE_3") && (config.system.output.type[tmpParam_editOutputId] == 3))) {
// add class 'visible' which overwrites display with flex!important and justify center
return String("visible");
} else {
return String();
}
}
String Proc_WebPage_system_sensor_add_POST(const String& var) {
if(var == "SAVE_MSG") {
return String(Common_HTML_SAVE_MSG);
} else {
return Proc_WebPage_system_output_add(var);
}
}
void WebPage_system_sensor_add(AsyncWebServerRequest *request) {
if(request->method() == HTTP_POST) {
Serial.println(":: [Webserver:system:output:add] [POST] hello");
byte outputId;
byte outputType;
if(request->hasParam("outputId", true)) {
const AsyncWebParameter* p_outputId = request->getParam("outputId", true);
Serial.printf(":: [Webserver:system] POST[%s]: %s\n", p_outputId->name().c_str(), p_outputId->value().c_str());
outputId = p_outputId->value().toInt();
}
if(request->hasParam("type", true)) {
const AsyncWebParameter* p_type = request->getParam("type", true);
Serial.printf(":: [Webserver:system] POST[%s]: %s\n", p_type->name().c_str(), p_type->value().c_str());
// put info config struct
config.system.output.type[outputId] = p_type->value().toInt();
// remember the value in own var to work later with here
outputType = p_type->value().toInt();
}
if(request->hasParam("device", true)) {
const AsyncWebParameter* p_device = request->getParam("device", true);
Serial.printf(":: [Webserver:system] POST[%s]: %s\n", p_device->name().c_str(), p_device->value().c_str());
config.system.output.device[outputId] = p_device->value().toInt();
}
if(request->hasParam("name", true)) {
const AsyncWebParameter* p_name = request->getParam("name", true);
Serial.printf(":: [Webserver:system] POST[%s]: %s\n", p_name->name().c_str(), p_name->value().c_str());
strlcpy(config.system.output.name[outputId], p_name->value().c_str(), sizeof(config.system.output.name[outputId]));
}
if(request->hasParam("enabled", true)) {
const AsyncWebParameter* p_enabled = request->getParam("enabled", true);
Serial.printf(":: [Webserver:system] POST[%s]: %s\n", p_enabled->name().c_str(), p_enabled->value().c_str());
config.system.output.enabled[outputId] = p_enabled->value().toInt();
}
// only fill the type related config vars
switch(outputType) {
// GPIO
case 1:
if(request->hasParam("gpio", true)) {
const AsyncWebParameter* p_gpio = request->getParam("gpio", true);
Serial.printf(":: [Webserver:system] POST[%s]: %s\n", p_gpio->name().c_str(), p_gpio->value().c_str());
config.system.output.gpio[outputId] = p_gpio->value().toInt();
}
if(request->hasParam("gpio_pwm", true)) {
const AsyncWebParameter* p_gpio_pwm = request->getParam("gpio_pwm", true);
Serial.printf(":: [Webserver:system] POST[%s]: %s\n", p_gpio_pwm->name().c_str(), p_gpio_pwm->value().c_str());
config.system.output.gpio_pwm[outputId] = p_gpio_pwm->value().toInt();
}
if(request->hasParam("gpio_invert", true)) {
const AsyncWebParameter* p_gpio_invert = request->getParam("gpio_invert", true);
Serial.printf(":: [Webserver:system] POST[%s]: %s\n", p_gpio_invert->name().c_str(), p_gpio_invert->value().c_str());
config.system.output.gpio_invert[outputId] = p_gpio_invert->value().toInt();
}
break;
// I2C
case 2:
if(request->hasParam("i2c", true)) {
const AsyncWebParameter* p_i2c = request->getParam("i2c", true);
Serial.printf(":: [Webserver:system] POST[%s]: %s\n", p_i2c->name().c_str(), p_i2c->value().c_str());
strlcpy(config.system.output.i2c[outputId], p_i2c->value().c_str(), sizeof(config.system.output.i2c[outputId]));
}
break;
// Webcall
case 3:
if(request->hasParam("webcall_host", true)) {
const AsyncWebParameter* p_webcall_host = request->getParam("webcall_host", true);
Serial.printf(":: [Webserver:system] POST[%s]: %s\n", p_webcall_host->name().c_str(), p_webcall_host->value().c_str());
strlcpy(config.system.output.webcall_host[outputId], p_webcall_host->value().c_str(), sizeof(config.system.output.webcall_host[outputId]));
}
if(request->hasParam("webcall_path_on", true)) {
const AsyncWebParameter* p_webcall_path_on = request->getParam("webcall_path_on", true);
Serial.printf(":: [Webserver:system] POST[%s]: %s\n", p_webcall_path_on->name().c_str(), p_webcall_path_on->value().c_str());
strlcpy(config.system.output.webcall_path_on[outputId], p_webcall_path_on->value().c_str(), sizeof(config.system.output.webcall_path_on[outputId]));
}
if(request->hasParam("webcall_path_off", true)) {
const AsyncWebParameter* p_webcall_path_off = request->getParam("webcall_path_off", true);
Serial.printf(":: [Webserver:system] POST[%s]: %s\n", p_webcall_path_off->name().c_str(), p_webcall_path_off->value().c_str());
strlcpy(config.system.output.webcall_path_off[outputId], p_webcall_path_off->value().c_str(), sizeof(config.system.output.webcall_path_off[outputId]));
}
break;
default: break;
}
SaveConfig();
// request->send_P(200, "text/html", Page_system_output_add_HTML, Proc_WebPage_system_output_add_POST);
// I like it more when user gets redirected to the output overview after saving
request->redirect("/system/output/?success");
} else {
if(request->hasParam("edit")) {
const AsyncWebParameter* p_edit = request->getParam("edit");
Serial.println("DB [Webserver:system:output:add?edit] ");
Serial.printf(":: [Webserver:system] POST[%s]: %d\n", p_edit->name().c_str(), p_edit->value().toInt());
tmpParam_editSensorId = p_edit->value().toInt();
request->send_P(200, "text/html", Page_system_sensor_add_HTML, Proc_WebPage_system_sensor_addEdit);
} else {
request->send_P(200, "text/html", Page_system_sensor_add_HTML, Proc_WebPage_system_sensor_add);
}
}
}

View file

@ -54,13 +54,14 @@ const char* Page_system_HTML PROGMEM = R"(%HEADER%
%FOOTER%)";
const char* Page_system_HTML_SUBNAV PROGMEM = R"(<ul class='subnav'>
<li><a class='%ACTIVE_SUBNAV_SENSOR%' href='/system/sensor/'>&#x1F321;&#xFE0F; Sensor configuration</a></li>
<li><a class='%ACTIVE_SUBNAV_OUTPUT%' href='/system/output/'>&#9889; Output configuration</a></li>
<li><a class='%ACTIVE_SUBNAV_UPDATE%' href='/system/update'>&#x1F504; Firmware update</a></li>
<li><a class='%ACTIVE_SUBNAV_RESTART%' href='/system/restart' >&#x1F501; CanGrow restart</a></li>
<li><a class='%ACTIVE_SUBNAV_WIPE%' href='/system/wipe' >&#x1F4A3; Factory reset</a></li>
</ul>)";
/*
/*******************************************************************************
* Subpage update
*/
const char* Page_system_update_HTML PROGMEM = R"(%HEADER%
@ -91,7 +92,7 @@ const char* Page_system_update_HTML_POST_FAILED PROGMEM = R"(<html>
Please see messages on serial monitor for more information and go back to <a href='/system/update'>\"System settings > Firmware update\"</a> and try another file.
</body></html>)";
/*
/*******************************************************************************
* Subpage restart
*/
const char* Page_system_restart_HTML PROGMEM = R"(%HEADER%
@ -111,7 +112,7 @@ const char* Page_system_restart_HTML_RESTART_MSG_POST PROGMEM = R"(Restarting...
/*
/*******************************************************************************
* Subpage wipe
*/
const char* Page_system_wipe_HTML PROGMEM = R"(%HEADER%
@ -132,7 +133,7 @@ Please confirm: <input type='checkbox' id='confirmed' name='confirmed' required
const char* Page_system_wipe_HTML_WIPE_MSG_POST PROGMEM = R"(Restarting...)";
/*
/*******************************************************************************
* Subpage output
*/
const char* Page_system_output_HTML PROGMEM = R"(%HEADER%
@ -152,7 +153,7 @@ const char* Page_system_output_HTML PROGMEM = R"(%HEADER%
</table>
%FOOTER%)";
/*
/*******************************************************************************
* Subpage output add
*/
const char* Page_system_output_add_HTML PROGMEM = R"(%HEADER%
@ -227,3 +228,114 @@ const char* Page_system_output_add_HTML PROGMEM = R"(%HEADER%
</form>
%FOOTER%)";
/*******************************************************************************
* Subpage sensor
*/
const char* Page_system_sensor_HTML PROGMEM = R"(%HEADER%
%SUBNAV%
%SAVE_MSG%
<a class='button' href='/system/sensor/add'>&#10133; Add output</a>
<table class='centered'>
<tr>
<th>ID</th>
<th>Name</th>
<th>Type</th>
<th>Device</th>
<th>Enabled</th>
<th>Action</th>
</tr>
%OUTPUT_TR_TD%
</table>
%FOOTER%)";
/*******************************************************************************
* Subpage sensor add
*/
const char* Page_system_sensor_add_HTML PROGMEM = R"(%HEADER%
%SUBNAV%
<h3>%ACTION% output ID %OUTPUT_ID%</h3>
%SAVE_MSG%
<p>Add/Edit CanGrow sensor.</p>
<form method='post' action='/system/sensor/add'>
<input type='hidden' name='outputId' value='%OUTPUT_ID%' />
<u>Type</u>:<br>
<select id='type_sel' name='type' onchange="showSelect('type_sel', 'type_', 'hidden');" required>
<option disabled value='' selected hidden>---</option>
%OUTPUT_TYPE%
</select><br>
<u>Device</u>:<br>
<select name='device' required>
<option disabled value='' selected hidden>---</option>
%OUTPUT_DEVICE%
</select><br>
<u>Name</u>:<br>
<input type='text' name='name' maxlength='16' value='%OUTPUT_NAME%' required><br>
<u>Enable</u>:<br>
<select name='enabled' required>
<option disabled value='' selected hidden>---</option>
%OUTPUT_ENABLED%
</select><br>
<div class='hidden %CLASS_TYPE_1%' id='type_1'>
<u>GPIO</u>:<br>
<select name='gpio'>
<option disabled value='' selected hidden>---</option>
%GPIO_INDEX%
</select><br>
<u>GPIO PWM</u>:<br>
<select name='gpio_pwm' >
<option disabled value='' selected hidden>---</option>
%GPIO_PWM%
</select><br>
<u>GPIO invert</u>:<br>
<select name='gpio_invert' >
<option disabled value='' selected hidden>---</option>
%GPIO_INVERT%
</select><br>
</div>
<div class='hidden %CLASS_TYPE_2%' id='type_2'>
<u>I2C</u>:<br>
<input type='text' name='i2c' maxlength='16' value='%I2C%' ><br>
</div>
<div class='hidden %CLASS_TYPE_3%' id='type_3'>
<u>Webcall host</u>:<br>
<input type='text' name='webcall_host' maxlength='32' value='%WEBCALL_HOST%' ><br>
<u>Webcall path 'on'</u>:<br>
<input type='text' name='webcall_path_on' maxlength='32' value='%WEBCALL_PATH_ON%' ><br>
<u>Webcall path 'off'</u>:<br>
<input type='text' name='webcall_path_off' maxlength='32' value='%WEBCALL_PATH_OFF%' ><br>
</div>
<br>
<input type='submit' value='&#x1F4BE; Save settings'>
</form>
%FOOTER%)";