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_Wifi.h"
#include "include/CanGrow_LittleFS.h"
#include "include/CanGrow_Webserver.h"
#include "include/CanGrow_Sensor.h"
#include "include/CanGrow_Webserver.h"
void setup() {
@ -142,16 +143,16 @@ void setup() {
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(i);
Serial.print(", Name '");
Serial.print(SensorIndex[i].name);
Serial.println("'");
Serial.println(":: [SETUP] Readings: ");
Serial.println("', Readings");
for(byte j = 0; j < SENSOR_MAX_READING; j++) {
if(SensorIndex[i].reading[j] > 0 ) {
Serial.print(":: [SETUP] - ");
Serial.print(":: [SETUP] ");
Serial.print(j);
Serial.print(": ");
Serial.print(Sensor_Reading_descr[SensorIndex[i].reading[j]]);

View file

@ -147,8 +147,6 @@ struct GPIO_Index {
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
*/
@ -218,31 +221,14 @@ struct Config_System_Output {
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
* -
* - type: Index ID of SensorIndex, which Sensor to use (ADC, BME280, Chirp, ...)
* - name: nice name
* - gpio: gpio to use for RPM reading, builtin ADC, OneWire
*/
byte type[Max_Outputs];
byte device[Max_Outputs];
char name[Max_Outputs][32];
byte type[Max_Sensors];
char name[Max_Sensors][32];
byte gpio[Max_Sensors];
};
/* main System struct */

View file

@ -73,6 +73,23 @@ byte Give_Free_OutputId() {
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) {
//}

View file

@ -205,9 +205,9 @@ bool LoadConfig() {
config.system.httpLogSerial = objSystem["httpLogSerial"];
config.system.schedulerInterval = objSystem["schedulerInterval"];
JsonObject objSystemOutput = objSystem["output"][0];
/* System Outputs */
JsonObject objSystemOutput = objSystem["output"][0];
for(byte i=0; i < Max_Outputs; i++) {
if(objSystemOutput["type"][i] > 0) {
config.system.output.type[i] = objSystemOutput["type"][i];
@ -227,6 +227,20 @@ bool LoadConfig() {
}
}
/* 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 */
JsonObject objGrow = doc["grow"][0];
strlcpy(config.grow.growName, objGrow["growName"], sizeof(config.grow.growName));
@ -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 */
JsonObject objGrow = doc["grow"].add<JsonObject>();

View file

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

View file

@ -26,3 +26,5 @@
* 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
// 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) {
for(byte i=0; i < Max_Sensors; i++) {
if(config.system.sensor.type[i] > 0) {
#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
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 += config.system.sensor.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 += SensorIndex[config.system.sensor.type[i]].name;
output_tr_td += "</td><td>";
// 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 += i;
output_tr_td += "'>";
@ -820,12 +816,12 @@ String Proc_WebPage_system_sensor(const String& var) {
// 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 += "<form class='linkForm' action='/system/sensor/' method='post'>";
output_tr_td += "<input type='hidden' name='delete_sensor' 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 += config.system.sensor.name[i];;
output_tr_td += "')\"></form>";
output_tr_td += "</td></tr>";
@ -842,42 +838,32 @@ 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);
return Proc_WebPage_system_sensor(var);
}
}
void WebPage_system_sensor(AsyncWebServerRequest *request) {
if(request->method() == HTTP_POST) {
if(request->hasParam("delete_output", true)) {
byte outputId;
if(request->hasParam("delete_sensor", true)) {
byte sensorId;
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());
const AsyncWebParameter* p_delete_sensor = request->getParam("delete_sensor", true);
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
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]);
config.system.sensor.type[sensorId] = 0;
memset(config.system.sensor.name[sensorId], '\0', sizeof config.system.sensor.name[sensorId]);
config.system.output.gpio[sensorId] = 0;
SaveConfig();
}
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 {
@ -897,20 +883,20 @@ void WebPage_system_sensor(AsyncWebServerRequest *request) {
/* returns select <option> list of available output types */
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
for(byte i = 1; i < Output_Type_total; i++) {
outputType_html += "<option value='";
outputType_html += i;
outputType_html += "'";
for(byte i = 1; i < SensorIndex_length; i++) {
sensorType_html += "<option value='";
sensorType_html += i;
sensorType_html += "'";
if(i == selectId) {
outputType_html += " selected";
sensorType_html += " selected";
}
outputType_html += ">";
outputType_html += Output_Type_descr[i];
outputType_html += "</option>";
sensorType_html += ">";
sensorType_html += SensorIndex[i].name;
sensorType_html += "</option>";
}
return outputType_html;
return sensorType_html;
}
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) {
#ifndef DEBUG
Serial.print("DB [Webserver:system:output:add(Proc)] var: ");
Serial.print("DB [Webserver:system:sensor:add(Proc)] var: ");
Serial.println(var);
#endif
if(TestHeaderFooter(var)) {
@ -945,29 +931,17 @@ String Proc_WebPage_system_sensor_add(const String& var) {
} else if(var == "ACTION") {
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
return String(Give_Free_OutputId());
return String(Give_Free_SensorId());
} 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 == "SENSOR_TYPE") {
return Html_SelOpt_type_WebPage_system_sensor_add();
} 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();
}
@ -1047,53 +1021,57 @@ 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);
return Proc_WebPage_system_sensor_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();
Serial.println(":: [Webserver:system:sensor:add] [POST] hello");
byte sensorId;
byte sensorType;
if(request->hasParam("sensorId", true)) {
const AsyncWebParameter* p_sensorId = request->getParam("sensorId", true);
Serial.printf(":: [Webserver:system] POST[%s]: %s\n", p_sensorId->name().c_str(), p_sensorId->value().c_str());
sensorId = p_sensorId->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();
config.system.sensor.type[sensorId] = 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("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[sensorId] = 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]));
strlcpy(config.system.sensor.name[sensorId], p_name->value().c_str(), sizeof(config.system.sensor.name[sensorId]));
}
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();
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.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
switch(outputType) {
// GPIO
/* switch(outputType) {
//GPIO
case 1:
if(request->hasParam("gpio", true)) {
const AsyncWebParameter* p_gpio = request->getParam("gpio", true);
@ -1114,7 +1092,7 @@ void WebPage_system_sensor_add(AsyncWebServerRequest *request) {
}
break;
// I2C
//I2C
case 2:
if(request->hasParam("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]));
}
break;
// Webcall
//Webcall
case 3:
if(request->hasParam("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;
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");
request->redirect("/system/sensor/?success");
} else {
if(request->hasParam("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());
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>Name</th>
<th>Type</th>
<th>Device</th>
<th>Enabled</th>
<th>Action</th>
</tr>
%OUTPUT_TR_TD%
</table>
@ -266,68 +263,40 @@ const char* Page_system_sensor_HTML PROGMEM = R"(%HEADER%
*/
const char* Page_system_sensor_add_HTML PROGMEM = R"(%HEADER%
%SUBNAV%
<h3>%ACTION% output ID %OUTPUT_ID%</h3>
<h3>%ACTION% sensor ID %SENSOR_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%' />
<input type='hidden' name='sensorId' value='%SENSOR_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%
%SENSOR_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%
<u>GPIO</u>:<br>
<select name='gpio'>
<option value='' selected >---</option>
%GPIO_INDEX%
</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>
<span>Special 1</span>
</div>
<div class='hidden %CLASS_TYPE_2%' id='type_2'>
<u>I2C</u>:<br>
<input type='text' name='i2c' maxlength='16' value='%I2C%' ><br>
<span>Special 2</span>
</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>
<span>Special 3</span>
</div>
<br>