basic sensor config works

This commit is contained in:
Marcus 2024-11-17 04:46:32 +01:00
parent 44c5b060d7
commit de0cf2390c
8 changed files with 155 additions and 172 deletions

View file

@ -82,8 +82,9 @@
#include "include/CanGrow_Core.h" #include "include/CanGrow_Core.h"
#include "include/CanGrow_Wifi.h" #include "include/CanGrow_Wifi.h"
#include "include/CanGrow_LittleFS.h" #include "include/CanGrow_LittleFS.h"
#include "include/CanGrow_Webserver.h"
#include "include/CanGrow_Sensor.h" #include "include/CanGrow_Sensor.h"
#include "include/CanGrow_Webserver.h"
void setup() { void setup() {
@ -142,16 +143,16 @@ void setup() {
Serial.println(":: [SETUP] Sensor drivers"); Serial.println(":: [SETUP] Sensor drivers");
for(byte i = 0; i < SensorIndex_length; i++) { for(byte i = 1; i <= SensorIndex_length; i++) {
Serial.print(":: [SETUP] Sensor Index "); Serial.print(":: [SETUP] Sensor Index ");
Serial.print(i); Serial.print(i);
Serial.print(", Name '"); Serial.print(", Name '");
Serial.print(SensorIndex[i].name); Serial.print(SensorIndex[i].name);
Serial.println("'"); Serial.println("', Readings");
Serial.println(":: [SETUP] Readings: ");
for(byte j = 0; j < SENSOR_MAX_READING; j++) { for(byte j = 0; j < SENSOR_MAX_READING; j++) {
if(SensorIndex[i].reading[j] > 0 ) { if(SensorIndex[i].reading[j] > 0 ) {
Serial.print(":: [SETUP] - "); Serial.print(":: [SETUP] ");
Serial.print(j); Serial.print(j);
Serial.print(": "); Serial.print(": ");
Serial.print(Sensor_Reading_descr[SensorIndex[i].reading[j]]); Serial.print(Sensor_Reading_descr[SensorIndex[i].reading[j]]);

View file

@ -147,8 +147,6 @@ struct GPIO_Index {
const byte note; const byte note;
}; };
const byte Max_Outputs = 16;
/* /*
* *
@ -156,6 +154,11 @@ const byte Max_Outputs = 16;
* *
*/ */
// define Max limits for outputs and sensors
const byte Max_Outputs = 16;
const byte Max_Sensors = 16;
/* /*
* Config WiFi * Config WiFi
*/ */
@ -218,31 +221,14 @@ struct Config_System_Output {
struct Config_System_Sensor { struct Config_System_Sensor {
/* /*
* Config System Sensor * Config System Sensor
* * - type: Index ID of SensorIndex, which Sensor to use (ADC, BME280, Chirp, ...)
* - Sensor Name * - name: nice name
* - Sensors can offer following types * - gpio: gpio to use for RPM reading, builtin ADC, OneWire
* - 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 type[Max_Sensors];
byte device[Max_Outputs]; char name[Max_Sensors][32];
char name[Max_Outputs][32]; byte gpio[Max_Sensors];
}; };
/* main System struct */ /* main System struct */

View file

@ -73,6 +73,23 @@ byte Give_Free_OutputId() {
return outputId_free; return outputId_free;
} }
byte Give_Free_SensorId() {
byte sensorId_free;
for(byte i=0; i < Max_Sensors; i++) {
if(config.system.sensor.type[i] > 0) {
// here i define that 255 stands for "no more free outputs"
sensorId_free = 255;
} else {
sensorId_free = i;
break;
}
}
#ifndef DEBUG
Serial.printf("DB [Core:Give_Free_SensorId] next free output id: %d\n", sensorId_free);
#endif
return sensorId_free;
}
//bool Check_OutputId_Used(byte outputId) { //bool Check_OutputId_Used(byte outputId) {
//} //}

View file

@ -205,9 +205,9 @@ bool LoadConfig() {
config.system.httpLogSerial = objSystem["httpLogSerial"]; config.system.httpLogSerial = objSystem["httpLogSerial"];
config.system.schedulerInterval = objSystem["schedulerInterval"]; config.system.schedulerInterval = objSystem["schedulerInterval"];
JsonObject objSystemOutput = objSystem["output"][0];
/* System Outputs */ /* System Outputs */
JsonObject objSystemOutput = objSystem["output"][0];
for(byte i=0; i < Max_Outputs; i++) { for(byte i=0; i < Max_Outputs; i++) {
if(objSystemOutput["type"][i] > 0) { if(objSystemOutput["type"][i] > 0) {
config.system.output.type[i] = objSystemOutput["type"][i]; config.system.output.type[i] = objSystemOutput["type"][i];
@ -226,6 +226,20 @@ bool LoadConfig() {
strlcpy(config.system.output.webcall_path_off[i], objSystemOutput["webcall_path_off"][i], sizeof(config.system.output.webcall_path_off[i])); strlcpy(config.system.output.webcall_path_off[i], objSystemOutput["webcall_path_off"][i], sizeof(config.system.output.webcall_path_off[i]));
} }
} }
/* System Sensors */
JsonObject objSystemSensor = objSystem["sensor"][0];
for(byte i=0; i < Max_Sensors; i++) {
if(objSystemSensor["type"][i] > 0) {
config.system.sensor.type[i] = objSystemSensor["type"][i];
strlcpy(config.system.sensor.name[i], objSystemSensor["name"][i], sizeof(config.system.sensor.name[i]));
// gpio
config.system.sensor.gpio[i] = objSystemSensor["gpio"][i];
}
}
/* Grow */ /* Grow */
JsonObject objGrow = doc["grow"][0]; JsonObject objGrow = doc["grow"][0];
@ -308,6 +322,17 @@ bool SaveConfig(bool writeToSerial = false) {
} }
} }
/* System Sensors */
JsonObject objSystemSensor = objSystem["sensor"].add<JsonObject>();
for(byte i=0; i < Max_Sensors; i++) {
if(config.system.sensor.type[i] > 0) {
objSystemSensor["type"][i] = config.system.sensor.type[i];
objSystemSensor["name"][i] = config.system.sensor.name[i];
objSystemSensor["gpio"][i] = config.system.sensor.gpio[i];
}
}
/* Grow */ /* Grow */
JsonObject objGrow = doc["grow"].add<JsonObject>(); JsonObject objGrow = doc["grow"].add<JsonObject>();

View file

@ -78,38 +78,43 @@ struct Sensor_Index {
* *
*/ */
const char name[32]; const char name[32];
byte reading[SENSOR_MAX_READING]; const byte reading[SENSOR_MAX_READING];
}; };
const byte SensorIndex_length = 4; const byte SensorIndex_length = 4;
Sensor_Index SensorIndex[] { Sensor_Index SensorIndex[] {
// 0 - first sensor // 0 is for unset in config
{ "internal ADC", { { "unset", {
SENSOR_READING_RAW, {},
}}, }},
// 1 // 1 - internal ADC
{ SENSOR_00_NAME, {
SENSOR_READING_RAW,
}},
// 2 - BME280
{ "BME280", { { "BME280", {
SENSOR_READING_TEMP, SENSOR_READING_TEMP,
SENSOR_READING_HUMIDITY, SENSOR_READING_HUMIDITY,
SENSOR_READING_PRESSURE, SENSOR_READING_PRESSURE,
}}, }},
// 2 // 3
{ "Chirp", { { "Chirp", {
SENSOR_READING_MOISTURE, SENSOR_READING_MOISTURE,
SENSOR_READING_TEMP, SENSOR_READING_TEMP,
SENSOR_READING_RAW, SENSOR_READING_RAW,
}}, }},
// 3 // 4
{ "AS1115", { { "ADS1115", {
SENSOR_READING_RAW, SENSOR_READING_RAW,
SENSOR_READING_RAW, SENSOR_READING_RAW,
SENSOR_READING_RAW, SENSOR_READING_RAW,
SENSOR_READING_RAW SENSOR_READING_RAW
}}, }},
// 4 // 5
}; };

View file

@ -26,3 +26,5 @@
* THE SOFTWARE. * THE SOFTWARE.
* *
*/ */
#define SENSOR_00_NAME "ADC builtin"

View file

@ -794,25 +794,21 @@ String Proc_WebPage_system_sensor(const String& var) {
// build table body // build table body
// i dont know a better way at the moment. if you do, please tell me! // i dont know a better way at the moment. if you do, please tell me!
String output_tr_td; String output_tr_td;
for(byte i=0; i < Max_Outputs; i++) { for(byte i=0; i < Max_Sensors; i++) {
if(config.system.output.type[i] > 0) { if(config.system.sensor.type[i] > 0) {
#ifndef DEBUG #ifndef DEBUG
Serial.printf("DB [Webserver:system:output(Proc)] OutputID %d Type %d\n", i, config.system.output.type[i]); Serial.printf("DB [Webserver:system:sensor(Proc)] sensorId %d Type %d\n", i, config.system.sensor.type[i]);
#endif #endif
output_tr_td += "<tr><td>"; output_tr_td += "<tr><td>";
output_tr_td += i; output_tr_td += i;
output_tr_td += "</td><td>"; output_tr_td += "</td><td>";
output_tr_td += config.system.output.name[i]; output_tr_td += config.system.sensor.name[i];
output_tr_td += "</td><td>"; output_tr_td += "</td><td>";
output_tr_td += Output_Type_descr[config.system.output.type[i]]; output_tr_td += SensorIndex[config.system.sensor.type[i]].name;
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>"; output_tr_td += "</td><td>";
// edit button // edit button
output_tr_td += "<form class='linkForm' action='/system/output/add' method='get'>"; output_tr_td += "<form class='linkForm' action='/system/sensor/add' method='get'>";
output_tr_td += "<input type='hidden' name='edit' value='"; output_tr_td += "<input type='hidden' name='edit' value='";
output_tr_td += i; output_tr_td += i;
output_tr_td += "'>"; output_tr_td += "'>";
@ -820,12 +816,12 @@ String Proc_WebPage_system_sensor(const String& var) {
// delete button // delete button
output_tr_td += "<form class='linkForm' action='/system/output/' method='post'>"; output_tr_td += "<form class='linkForm' action='/system/sensor/' method='post'>";
output_tr_td += "<input type='hidden' name='delete_output' value='"; output_tr_td += "<input type='hidden' name='delete_sensor' value='";
output_tr_td += i; output_tr_td += i;
output_tr_td += "'>"; output_tr_td += "'>";
output_tr_td += "<input type='submit' value='&#x274C;' onclick=\"return confirmDelete('"; output_tr_td += "<input type='submit' value='&#x274C;' onclick=\"return confirmDelete('";
output_tr_td += config.system.output.name[i];; output_tr_td += config.system.sensor.name[i];;
output_tr_td += "')\"></form>"; output_tr_td += "')\"></form>";
output_tr_td += "</td></tr>"; output_tr_td += "</td></tr>";
@ -842,42 +838,32 @@ String Proc_WebPage_system_sensor_POST(const String& var) {
if(var == "SAVE_MSG") { if(var == "SAVE_MSG") {
return String(Common_HTML_SAVE_MSG); return String(Common_HTML_SAVE_MSG);
} else { } else {
return Proc_WebPage_system_output(var); return Proc_WebPage_system_sensor(var);
} }
} }
void WebPage_system_sensor(AsyncWebServerRequest *request) { void WebPage_system_sensor(AsyncWebServerRequest *request) {
if(request->method() == HTTP_POST) { if(request->method() == HTTP_POST) {
if(request->hasParam("delete_output", true)) { if(request->hasParam("delete_sensor", true)) {
byte outputId; byte sensorId;
const AsyncWebParameter* p_delete_output = request->getParam("delete_output", true); const AsyncWebParameter* p_delete_sensor = request->getParam("delete_sensor", true);
Serial.printf(":: [Webserver:system:output] POST[%s]: %s\n", p_delete_output->name().c_str(), p_delete_output->value().c_str()); Serial.printf(":: [Webserver:system:sensor] POST[%s]: %s\n", p_delete_sensor->name().c_str(), p_delete_sensor->value().c_str());
outputId = p_delete_output->value().toInt(); sensorId = p_delete_sensor->value().toInt();
Serial.printf(":: [Webserver:system:output] Deleting output: %d\n", outputId); Serial.printf(":: [Webserver:system:output] Deleting output: %d\n", sensorId);
// we ensure that every field is empty // we ensure that every field is empty
config.system.output.type[outputId] = 0; config.system.sensor.type[sensorId] = 0;
config.system.output.device[outputId] = 0; memset(config.system.sensor.name[sensorId], '\0', sizeof config.system.sensor.name[sensorId]);
// set every field of char array to 0x00 with memset config.system.output.gpio[sensorId] = 0;
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(); SaveConfig();
} }
request->send_P(200, "text/html", Page_system_sensor_HTML, Proc_WebPage_system_sensor_POST); request->send_P(200, "text/html", Page_system_sensor_HTML, Proc_WebPage_system_sensor_POST);
Serial.println(":: [Webserver:system:output] [POST] hello"); Serial.println(":: [Webserver:system:sensor] [POST] hello");
} else { } else {
@ -897,20 +883,20 @@ void WebPage_system_sensor(AsyncWebServerRequest *request) {
/* returns select <option> list of available output types */ /* returns select <option> list of available output types */
String Html_SelOpt_type_WebPage_system_sensor_add(byte selectId = 255) { String Html_SelOpt_type_WebPage_system_sensor_add(byte selectId = 255) {
String outputType_html; String sensorType_html;
// go through all available Output Devices, skip 0 because it means unconfigured // go through all available Output Devices, skip 0 because it means unconfigured
for(byte i = 1; i < Output_Type_total; i++) { for(byte i = 1; i < SensorIndex_length; i++) {
outputType_html += "<option value='"; sensorType_html += "<option value='";
outputType_html += i; sensorType_html += i;
outputType_html += "'"; sensorType_html += "'";
if(i == selectId) { if(i == selectId) {
outputType_html += " selected"; sensorType_html += " selected";
} }
outputType_html += ">"; sensorType_html += ">";
outputType_html += Output_Type_descr[i]; sensorType_html += SensorIndex[i].name;
outputType_html += "</option>"; sensorType_html += "</option>";
} }
return outputType_html; return sensorType_html;
} }
String Html_SelOpt_device_WebPage_system_sensor_add(byte selectId = 255) { String Html_SelOpt_device_WebPage_system_sensor_add(byte selectId = 255) {
@ -935,7 +921,7 @@ String Html_SelOpt_device_WebPage_system_sensor_add(byte selectId = 255) {
String Proc_WebPage_system_sensor_add(const String& var) { String Proc_WebPage_system_sensor_add(const String& var) {
#ifndef DEBUG #ifndef DEBUG
Serial.print("DB [Webserver:system:output:add(Proc)] var: "); Serial.print("DB [Webserver:system:sensor:add(Proc)] var: ");
Serial.println(var); Serial.println(var);
#endif #endif
if(TestHeaderFooter(var)) { if(TestHeaderFooter(var)) {
@ -945,29 +931,17 @@ String Proc_WebPage_system_sensor_add(const String& var) {
} else if(var == "ACTION") { } else if(var == "ACTION") {
return String("&#10133; Add"); return String("&#10133; Add");
} else if(var == "OUTPUT_ID") { } else if(var == "SENSOR_ID") {
// we check which id is free. A free ID as type == 0 // we check which id is free. A free ID as type == 0
return String(Give_Free_OutputId()); return String(Give_Free_SensorId());
} else if(var == "OUTPUT_TYPE") { } else if(var == "SENSOR_TYPE") {
return Html_SelOpt_type_WebPage_system_output_add(); return Html_SelOpt_type_WebPage_system_sensor_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") { } else if(var == "GPIO_INDEX") {
return Html_SelectOpt_GPIOindex(); return Html_SelectOpt_GPIOindex();
} else if(var == "GPIO_PWM") {
return Html_SelectOpt_bool();
} else if(var == "GPIO_INVERT") {
return Html_SelectOpt_bool();
} else { } else {
return String(); return String();
} }
@ -1047,53 +1021,57 @@ String Proc_WebPage_system_sensor_add_POST(const String& var) {
if(var == "SAVE_MSG") { if(var == "SAVE_MSG") {
return String(Common_HTML_SAVE_MSG); return String(Common_HTML_SAVE_MSG);
} else { } else {
return Proc_WebPage_system_output_add(var); return Proc_WebPage_system_sensor_add(var);
} }
} }
void WebPage_system_sensor_add(AsyncWebServerRequest *request) { void WebPage_system_sensor_add(AsyncWebServerRequest *request) {
if(request->method() == HTTP_POST) { if(request->method() == HTTP_POST) {
Serial.println(":: [Webserver:system:output:add] [POST] hello"); Serial.println(":: [Webserver:system:sensor:add] [POST] hello");
byte outputId; byte sensorId;
byte outputType; byte sensorType;
if(request->hasParam("outputId", true)) { if(request->hasParam("sensorId", true)) {
const AsyncWebParameter* p_outputId = request->getParam("outputId", true); const AsyncWebParameter* p_sensorId = request->getParam("sensorId", true);
Serial.printf(":: [Webserver:system] POST[%s]: %s\n", p_outputId->name().c_str(), p_outputId->value().c_str()); Serial.printf(":: [Webserver:system] POST[%s]: %s\n", p_sensorId->name().c_str(), p_sensorId->value().c_str());
outputId = p_outputId->value().toInt(); sensorId = p_sensorId->value().toInt();
} }
if(request->hasParam("type", true)) { if(request->hasParam("type", true)) {
const AsyncWebParameter* p_type = request->getParam("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()); Serial.printf(":: [Webserver:system] POST[%s]: %s\n", p_type->name().c_str(), p_type->value().c_str());
// put info config struct // put info config struct
config.system.output.type[outputId] = p_type->value().toInt(); config.system.sensor.type[sensorId] = 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)) { //if(request->hasParam("device", true)) {
const AsyncWebParameter* p_device = request->getParam("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()); //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(); //config.system.output.device[sensorId] = p_device->value().toInt();
} //}
if(request->hasParam("name", true)) { if(request->hasParam("name", true)) {
const AsyncWebParameter* p_name = request->getParam("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()); 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])); strlcpy(config.system.sensor.name[sensorId], p_name->value().c_str(), sizeof(config.system.sensor.name[sensorId]));
} }
if(request->hasParam("enabled", true)) { if(request->hasParam("gpio", true)) {
const AsyncWebParameter* p_enabled = request->getParam("enabled", true); const AsyncWebParameter* p_gpio = request->getParam("gpio", true);
Serial.printf(":: [Webserver:system] POST[%s]: %s\n", p_enabled->name().c_str(), p_enabled->value().c_str()); Serial.printf(":: [Webserver:system] POST[%s]: %s\n", p_gpio->name().c_str(), p_gpio->value().c_str());
config.system.output.enabled[outputId] = p_enabled->value().toInt(); config.system.sensor.gpio[sensorId] = p_gpio->value().toInt();
} }
//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 // only fill the type related config vars
switch(outputType) { /* switch(outputType) {
// GPIO //GPIO
case 1: case 1:
if(request->hasParam("gpio", true)) { if(request->hasParam("gpio", true)) {
const AsyncWebParameter* p_gpio = request->getParam("gpio", true); const AsyncWebParameter* p_gpio = request->getParam("gpio", true);
@ -1114,7 +1092,7 @@ void WebPage_system_sensor_add(AsyncWebServerRequest *request) {
} }
break; break;
// I2C //I2C
case 2: case 2:
if(request->hasParam("i2c", true)) { if(request->hasParam("i2c", true)) {
const AsyncWebParameter* p_i2c = request->getParam("i2c", true); const AsyncWebParameter* p_i2c = request->getParam("i2c", true);
@ -1122,7 +1100,7 @@ void WebPage_system_sensor_add(AsyncWebServerRequest *request) {
strlcpy(config.system.output.i2c[outputId], p_i2c->value().c_str(), sizeof(config.system.output.i2c[outputId])); strlcpy(config.system.output.i2c[outputId], p_i2c->value().c_str(), sizeof(config.system.output.i2c[outputId]));
} }
break; break;
// Webcall //Webcall
case 3: case 3:
if(request->hasParam("webcall_host", true)) { if(request->hasParam("webcall_host", true)) {
const AsyncWebParameter* p_webcall_host = request->getParam("webcall_host", true); const AsyncWebParameter* p_webcall_host = request->getParam("webcall_host", true);
@ -1145,20 +1123,20 @@ void WebPage_system_sensor_add(AsyncWebServerRequest *request) {
break; break;
default: break; default: break;
} }
*/
SaveConfig(); SaveConfig();
// request->send_P(200, "text/html", Page_system_output_add_HTML, Proc_WebPage_system_output_add_POST); // 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 // I like it more when user gets redirected to the output overview after saving
request->redirect("/system/output/?success"); request->redirect("/system/sensor/?success");
} else { } else {
if(request->hasParam("edit")) { if(request->hasParam("edit")) {
const AsyncWebParameter* p_edit = request->getParam("edit"); const AsyncWebParameter* p_edit = request->getParam("edit");
Serial.println("DB [Webserver:system:output:add?edit] "); Serial.println("DB [Webserver:system:sensor:add?edit] ");
Serial.printf(":: [Webserver:system] POST[%s]: %d\n", p_edit->name().c_str(), p_edit->value().toInt()); Serial.printf(":: [Webserver:system] POST[%s]: %d\n", p_edit->name().c_str(), p_edit->value().toInt());
tmpParam_editSensorId = p_edit->value().toInt(); tmpParam_editSensorId = p_edit->value().toInt();

View file

@ -253,9 +253,6 @@ const char* Page_system_sensor_HTML PROGMEM = R"(%HEADER%
<th>ID</th> <th>ID</th>
<th>Name</th> <th>Name</th>
<th>Type</th> <th>Type</th>
<th>Device</th>
<th>Enabled</th>
<th>Action</th>
</tr> </tr>
%OUTPUT_TR_TD% %OUTPUT_TR_TD%
</table> </table>
@ -266,68 +263,40 @@ const char* Page_system_sensor_HTML PROGMEM = R"(%HEADER%
*/ */
const char* Page_system_sensor_add_HTML PROGMEM = R"(%HEADER% const char* Page_system_sensor_add_HTML PROGMEM = R"(%HEADER%
%SUBNAV% %SUBNAV%
<h3>%ACTION% output ID %OUTPUT_ID%</h3> <h3>%ACTION% sensor ID %SENSOR_ID%</h3>
%SAVE_MSG% %SAVE_MSG%
<p>Add/Edit CanGrow sensor.</p> <p>Add/Edit CanGrow sensor.</p>
<form method='post' action='/system/sensor/add'> <form method='post' action='/system/sensor/add'>
<input type='hidden' name='outputId' value='%OUTPUT_ID%' /> <input type='hidden' name='sensorId' value='%SENSOR_ID%' />
<u>Type</u>:<br> <u>Type</u>:<br>
<select id='type_sel' name='type' onchange="showSelect('type_sel', 'type_', 'hidden');" required> <select id='type_sel' name='type' onchange="showSelect('type_sel', 'type_', 'hidden');" required>
<option disabled value='' selected hidden>---</option> <option disabled value='' selected hidden>---</option>
%OUTPUT_TYPE% %SENSOR_TYPE%
</select><br> </select><br>
<u>Device</u>:<br>
<select name='device' required>
<option disabled value='' selected hidden>---</option>
%OUTPUT_DEVICE%
</select><br>
<u>Name</u>:<br> <u>Name</u>:<br>
<input type='text' name='name' maxlength='16' value='%OUTPUT_NAME%' required><br> <input type='text' name='name' maxlength='16' value='%OUTPUT_NAME%' required><br>
<u>Enable</u>:<br> <u>GPIO</u>:<br>
<select name='enabled' required> <select name='gpio'>
<option disabled value='' selected hidden>---</option> <option value='' selected >---</option>
%OUTPUT_ENABLED% %GPIO_INDEX%
</select><br> </select><br>
<div class='hidden %CLASS_TYPE_1%' id='type_1'> <div class='hidden %CLASS_TYPE_1%' id='type_1'>
<u>GPIO</u>:<br> <span>Special 1</span>
<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>
<div class='hidden %CLASS_TYPE_2%' id='type_2'> <div class='hidden %CLASS_TYPE_2%' id='type_2'>
<u>I2C</u>:<br> <span>Special 2</span>
<input type='text' name='i2c' maxlength='16' value='%I2C%' ><br>
</div> </div>
<div class='hidden %CLASS_TYPE_3%' id='type_3'> <div class='hidden %CLASS_TYPE_3%' id='type_3'>
<u>Webcall host</u>:<br> <span>Special 3</span>
<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> </div>
<br> <br>