implement checks if gpio is free when adding new output

This commit is contained in:
Marcus 2024-10-26 16:54:39 +02:00
parent 22c316edbb
commit c8247268cc
6 changed files with 140 additions and 75 deletions

View file

@ -149,43 +149,7 @@ void loop() {
if((digitalRead(PinWIPE) != PinWIPE_default) && (alrdySaved == false)) { if((digitalRead(PinWIPE) != PinWIPE_default) && (alrdySaved == false)) {
Serial.println(":: [LOOP] PinWIPE is triggered, saving config.json and set config.system.httpLogSerial to true"); Serial.println(":: [LOOP] PinWIPE is triggered");
config.system.httpLogSerial = true;
// testing output save stuff
Serial.println(":: [LOOP] save output 0");
byte i = 0;
config.system.output.type[i] = 1;
config.system.output.device[i] = 1;
strlcpy(config.system.output.name[i], "bla", sizeof("bla"));
config.system.output.gpio[i] = 3;
config.system.output.gpio_invert[i] = false;
config.system.output.gpio_pwm[i] = false;
strlcpy(config.system.output.i2c[i], "0x3", sizeof("0x3"));
for(byte j=0; j < 4 ; j++) {
config.system.output.ip[i][j] = j + 3;
}
strlcpy(config.system.output.ip_path[i], "/asd?foo=lol", sizeof("/asd?foo=lol"));
config.system.output.enabled[i] = true;
Serial.println(":: [LOOP] save output 1");
i = 1;
config.system.output.type[i] = 2;
config.system.output.device[i] = 3;
strlcpy(config.system.output.name[i], "lol", sizeof("lol"));
config.system.output.gpio[i] = 5;
config.system.output.gpio_invert[i] = true;
config.system.output.gpio_pwm[i] = true;
strlcpy(config.system.output.i2c[i], "0x69", sizeof("0x69"));
for(byte j=0; j < 4 ; j++) {
config.system.output.ip[i][j] = j + 23;
}
strlcpy(config.system.output.ip_path[i], "/toggle_switch?on=true", sizeof("/toggle_switch?on=true"));
config.system.output.enabled[i] = true;
// save config to littlefs as json // save config to littlefs as json
SaveConfig(); SaveConfig();
// only print json to serial // only print json to serial

View file

@ -70,6 +70,10 @@ const byte INPUT_ONLY = 4;
const byte NO_PWM = 5; const byte NO_PWM = 5;
const byte HIGH_BOOT = 6; const byte HIGH_BOOT = 6;
const byte OUTPUT_TYPE_GPIO = 1;
const byte OUTPUT_TYPE_I2C = 2;
const byte OUTPUT_TYPE_WEB = 3;
struct GPIO_Index { struct GPIO_Index {
const byte gpio; const byte gpio;
const byte note; const byte note;
@ -110,7 +114,7 @@ struct Config_System_Output {
* - output_type: output type like GPIO, I2C, URL * - output_type: output type like GPIO, I2C, URL
* 1 - GPIO * 1 - GPIO
* 2 - I2C * 2 - I2C
* 3 - URL * 3 - Web
* - device: what this output is connected to * - device: what this output is connected to
* 1 - Light * 1 - Light
* 2 - Fan * 2 - Fan
@ -118,25 +122,29 @@ struct Config_System_Output {
* 4 - Humudifier * 4 - Humudifier
* 5 - Dehumidifier * 5 - Dehumidifier
* 6 - Heating * 6 - Heating
* - name: name of output
* - enabled: enable output
* - gpio: which gpio is used * - gpio: which gpio is used
* - gpio_invert: invert gpio output * - gpio_invert: invert gpio output
* - gpio_pwm: enable pwm for output * - gpio_pwm: enable pwm for output
* - i2c: * - i2c:
* - ip: ip to smart plug (tasmota e.g.) * - web_host: ip to smart plug (tasmota e.g.)
* - ip_path: uri path * - web_req_on: GET request path to turn ON
* - enabled: enable output * - web_req_off: GET request path to turn ON
* *
*/ */
byte type[Max_Outputs]; byte type[Max_Outputs];
byte device[Max_Outputs]; byte device[Max_Outputs];
char name[Max_Outputs][32]; char name[Max_Outputs][32];
bool enabled[Max_Outputs];
byte gpio[Max_Outputs]; byte gpio[Max_Outputs];
bool gpio_invert[Max_Outputs]; bool gpio_invert[Max_Outputs];
bool gpio_pwm[Max_Outputs]; bool gpio_pwm[Max_Outputs];
char i2c[Max_Outputs][8]; char i2c[Max_Outputs][8];
byte ip[Max_Outputs][4]; char web_host[Max_Outputs][32];
char ip_path[Max_Outputs][32]; char web_req_on[Max_Outputs][32];
bool enabled[Max_Outputs]; char web_req_off[Max_Outputs][32];
}; };
/* main System struct */ /* main System struct */

View file

@ -30,7 +30,7 @@
// blink fast with the built in LED in an infinite loop // blink fast with the built in LED in an infinite loop
void Restart() { void Restart() {
Serial.println(":: [Restart] got triggered, restarting in 2 seconds"); Serial.println(":: [Core:Restart] got triggered, restarting in 2 seconds");
byte i = 0; byte i = 0;
while(i <= 16) { while(i <= 16) {
if(i % 2) { if(i % 2) {
@ -55,3 +55,60 @@ char* IP2Char(IPAddress ipaddr){
sprintf(buffer, "%d.%d.%d.%d", ipaddr[0], ipaddr[1], ipaddr[2], ipaddr[3] ); sprintf(buffer, "%d.%d.%d.%d", ipaddr[0], ipaddr[1], ipaddr[2], ipaddr[3] );
return buffer; return buffer;
} }
byte Give_Free_OutputId() {
byte outputId_free;
for(byte i=0; i < Max_Outputs; i++) {
if(config.system.output.type[i] > 0) {
// here i define that 255 stands for "no more free outputs"
outputId_free = 255;
} else {
outputId_free = i;
break;
}
}
#ifndef DEBUG
Serial.printf("DB [Core:Give_Free_OutputId] next free output id: %d\n", outputId_free);
#endif
return outputId_free;
}
//bool Check_OutputId_Used(byte outputId) {
//}
// checks if GPIO is already in use by output or sensor
bool Check_GPIOindex_Used(byte gpio) {
bool used;
#ifndef DEBUG
Serial.printf("DB [Core:Check_GPIOindex_Used] check GPIO: %d\n", gpio);
#endif
// go through each outputid
for(byte i=0; i < Max_Outputs; i++) {
#ifndef DEBUG
//Serial.printf("DB [Core:Check_GPIOindex_Used] OutputId: %d , type: %d\n", i, config.system.output.type[i]);
#endif
// check if output type is gpio
if(config.system.output.type[i] == OUTPUT_TYPE_GPIO) {
#ifndef DEBUG
Serial.printf("DB [Core:Check_GPIOindex_Used] OutputId: %d is GPIO (type %d)\n", i, config.system.output.type[i]);
#endif
// check if gpio id is already in use
if(config.system.output.gpio[i] == gpio) {
#ifndef DEBUG
Serial.printf("DB [Core:Check_GPIOindex_Used] output.gpio[%d](%d) == GPIO %d\n", i, config.system.output.gpio[i], gpio);
#endif
used = true;
break;
} else {
used = false;
}
}
}
#ifndef DEBUG
Serial.printf("DB [Core:Check_GPIOindex_Used] GPIO: %d, used: %d\n", gpio, used);
#endif
// check sensors
return used;
}

View file

@ -213,15 +213,17 @@ bool LoadConfig() {
config.system.output.type[i] = objSystemOutput["type"][i]; config.system.output.type[i] = objSystemOutput["type"][i];
config.system.output.device[i] = objSystemOutput["device"][i]; config.system.output.device[i] = objSystemOutput["device"][i];
strlcpy(config.system.output.name[i], objSystemOutput["name"][i], sizeof(config.system.output.name[i])); strlcpy(config.system.output.name[i], objSystemOutput["name"][i], sizeof(config.system.output.name[i]));
config.system.output.enabled[i] = objSystemOutput["enabled"][i];
// gpio
config.system.output.gpio[i] = objSystemOutput["gpio"][i]; config.system.output.gpio[i] = objSystemOutput["gpio"][i];
config.system.output.gpio_invert[i] = objSystemOutput["gpio_invert"][i]; config.system.output.gpio_invert[i] = objSystemOutput["gpio_invert"][i];
config.system.output.gpio_pwm[i] = objSystemOutput["gpio_pwm"][i]; config.system.output.gpio_pwm[i] = objSystemOutput["gpio_pwm"][i];
// i2c
strlcpy(config.system.output.i2c[i], objSystemOutput["i2c"][i], sizeof(config.system.output.i2c[i])); strlcpy(config.system.output.i2c[i], objSystemOutput["i2c"][i], sizeof(config.system.output.i2c[i]));
for(byte j=0; j < 4 ; j++) { // web
config.system.output.ip[i][j] = objSystemOutput["ip"][i][j]; strlcpy(config.system.output.web_host[i], objSystemOutput["web_host"][i], sizeof(config.system.output.web_host[i]));
} strlcpy(config.system.output.web_req_on[i], objSystemOutput["web_req_on"][i], sizeof(config.system.output.web_req_on[i]));
strlcpy(config.system.output.ip_path[i], objSystemOutput["ip_path"][i], sizeof(config.system.output.ip_path[i])); strlcpy(config.system.output.web_req_off[i], objSystemOutput["web_req_off"][i], sizeof(config.system.output.web_req_off[i]));
config.system.output.enabled[i] = objSystemOutput["enabled"][i];
} }
} }
@ -291,16 +293,18 @@ bool SaveConfig(bool writeToSerial = false) {
objSystemOutput["type"][i] = config.system.output.type[i]; objSystemOutput["type"][i] = config.system.output.type[i];
objSystemOutput["device"][i] = config.system.output.device[i]; objSystemOutput["device"][i] = config.system.output.device[i];
objSystemOutput["name"][i] = config.system.output.name[i]; objSystemOutput["name"][i] = config.system.output.name[i];
objSystemOutput["enabled"][i] = config.system.output.enabled[i];
// gpio
objSystemOutput["gpio"][i] = config.system.output.gpio[i]; objSystemOutput["gpio"][i] = config.system.output.gpio[i];
objSystemOutput["gpio_invert"][i] = config.system.output.gpio_invert[i]; objSystemOutput["gpio_invert"][i] = config.system.output.gpio_invert[i];
objSystemOutput["gpio_pwm"][i] = config.system.output.gpio_pwm[i]; objSystemOutput["gpio_pwm"][i] = config.system.output.gpio_pwm[i];
// i2c
objSystemOutput["i2c"][i] = config.system.output.i2c[i]; objSystemOutput["i2c"][i] = config.system.output.i2c[i];
// web
objSystemOutput["web_host"][i] = config.system.output.web_host[i];
objSystemOutput["web_req_on"][i] = config.system.output.web_req_on[i];
objSystemOutput["web_req_off"][i] = config.system.output.web_req_off[i];
for(byte j=0; j < 4 ; j++) {
objSystemOutput["ip"][i][j] = config.system.output.ip[i][j];
}
objSystemOutput["ip_path"][i] = config.system.output.ip_path[i];
objSystemOutput["enabled"][i] = config.system.output.enabled[i];
} }
} }

View file

@ -365,26 +365,20 @@ String Proc_WebPage_system_output_add(const String& var) {
return Proc_WebPage_system_SUBNAV(var, 1); return Proc_WebPage_system_SUBNAV(var, 1);
} else if(var == "OUTPUT_ID") { } else if(var == "OUTPUT_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
byte freeOutputId; return String(Give_Free_OutputId());
for(byte i=0; i < Max_Outputs; i++) {
if(config.system.output.type[i] > 0) {
// here i define that 255 stands for "not available"
freeOutputId = 255;
} else {
freeOutputId = i;
break;
}
}
Serial.printf("DB [Webserver:system:output:add(Proc)] next free output id: %d\n", freeOutputId);
return String(freeOutputId);
} else if(var == "GPIO_INDEX") { } else if(var == "GPIO_INDEX") {
String gpioIndex_html; String gpioIndex_html;
for(byte i = 0; i < GPIOindex_length; i++) { for(byte i = 0; i < GPIOindex_length; i++) {
gpioIndex_html += "<option value='"; gpioIndex_html += "<option value='";
gpioIndex_html += i; gpioIndex_html += i;
gpioIndex_html += "'>GPIO "; gpioIndex_html += "'";
// set disabled option of gpio is already in use
if(Check_GPIOindex_Used(i) == true) {
gpioIndex_html += " disabled";
}
gpioIndex_html += ">GPIO ";
gpioIndex_html += GPIOindex[i].gpio; gpioIndex_html += GPIOindex[i].gpio;
//add gpio note if there is some //add gpio note if there is some
if(GPIOindex[i].note > 0) { if(GPIOindex[i].note > 0) {
@ -398,6 +392,10 @@ String Proc_WebPage_system_output_add(const String& var) {
default: break; default: break;
} }
} }
// add USED if gpio is already in use
if(Check_GPIOindex_Used(i) == true) {
gpioIndex_html += " USED";
}
gpioIndex_html += "</option>"; gpioIndex_html += "</option>";
@ -444,6 +442,7 @@ void WebPage_system_output_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:output:add] [POST] hello");
byte outputId; byte outputId;
byte outputType;
if(request->hasParam("outputId", true)) { if(request->hasParam("outputId", true)) {
const AsyncWebParameter* p_outputId = request->getParam("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()); Serial.printf(":: [Webserver:system] POST[%s]: %s\n", p_outputId->name().c_str(), p_outputId->value().c_str());
@ -453,7 +452,11 @@ void WebPage_system_output_add(AsyncWebServerRequest *request) {
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
config.system.output.type[outputId] = p_type->value().toInt(); 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)) { if(request->hasParam("device", true)) {
@ -474,6 +477,28 @@ void WebPage_system_output_add(AsyncWebServerRequest *request) {
config.system.output.enabled[outputId] = p_enabled->value().toInt(); config.system.output.enabled[outputId] = p_enabled->value().toInt();
} }
// only fill gpio values if type is GPIO
if(outputType == 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();
}
}
SaveConfig(); SaveConfig();
AsyncWebServerResponse *response = request->beginChunkedResponse("text/html", Chunk_system_output_add_HTML, Proc_WebPage_system_output_add_POST); AsyncWebServerResponse *response = request->beginChunkedResponse("text/html", Chunk_system_output_add_HTML, Proc_WebPage_system_output_add_POST);

View file

@ -202,7 +202,14 @@ const char* Page_system_output_add_HTML PROGMEM = R"(%HEADER%
<select name='gpio_pwm' > <select name='gpio_pwm' >
<option disabled value='' selected hidden>---</option> <option disabled value='' selected hidden>---</option>
<option value='1'>Enable</option> <option value='1'>Enable</option>
<option value='2'>Disable</option> <option value='0'>Disable</option>
</select><br>
<u>GPIO invert</u>:<br>
<select name='gpio_invert' >
<option disabled value='' selected hidden>---</option>
<option value='1'>Yes</option>
<option value='0'>No</option>
</select><br> </select><br>
</div> </div>
@ -213,14 +220,14 @@ const char* Page_system_output_add_HTML PROGMEM = R"(%HEADER%
</div> </div>
<div class='hidden' id='type_3'> <div class='hidden' id='type_3'>
<u>Host</u>:<br> <u>Web</u>:<br>
<input type='text' name='host' maxlength='16' value='' ><br> <input type='text' name='web_host' maxlength='32' value='' ><br>
<u>URI on</u>:<br> <u>URI on</u>:<br>
<input type='text' name='req_on' maxlength='16' value='' ><br> <input type='text' name='web_req_on' maxlength='32' value='' ><br>
<u>URI off</u>:<br> <u>URI off</u>:<br>
<input type='text' name='req_off' maxlength='16' value='' ><br> <input type='text' name='web_req_off' maxlength='32' value='' ><br>
</div> </div>
<br> <br>