[GH-ISSUE #1378] QUESTION: Can we add custom wepage to the menu? #1182

Open
opened 2026-02-28 01:28:53 +03:00 by kerem · 9 comments
Owner

Originally created by @Renison-Gohel on GitHub (Mar 27, 2022).
Original GitHub issue: https://github.com/tzapu/WiFiManager/issues/1378

How could we add custom html webpage to the main menu of configuration page and redirect to specific web address like /custompage when user click on newly add ( created ) custom button on the main page. is that possible with-in wifi manager? @tzapu @tablatronix

Originally created by @Renison-Gohel on GitHub (Mar 27, 2022). Original GitHub issue: https://github.com/tzapu/WiFiManager/issues/1378 **How could we add custom html webpage** to the main menu of configuration page and **redirect to specific web address like** **_/custompage_** when user click on newly add ( created ) custom button on the main page. is that possible with-in wifi manager? @tzapu @tablatronix
Author
Owner

@tablatronix commented on GitHub (Mar 27, 2022):

Yes, not straightforward but you can do it. Let me work up an example

<!-- gh-comment-id:1079944885 --> @tablatronix commented on GitHub (Mar 27, 2022): Yes, not straightforward but you can do it. Let me work up an example
Author
Owner

@zen85 commented on GitHub (Mar 29, 2022):

i am really looking forward to it since its something i only had limited success with for some time now. thanks for the great work!

<!-- gh-comment-id:1081630924 --> @zen85 commented on GitHub (Mar 29, 2022): i am really looking forward to it since its something i only had limited success with for some time now. thanks for the great work!
Author
Owner

@tablatronix commented on GitHub (Mar 29, 2022):

ok you could do it before, but you had to edit the strings code. You can still do it like that but I added a way to do it via code now.

you will have to enable the custom menu item via setMenu put it where you want in the order.
then set the custom menu item html ( can be many buttons or anything really )

The only issue is that you are limited to the one menu item, which CAN be contiguous buttons, so not a big deal as you can hack in html anyway to workaround it )


void bindServerCallback(){
  wm.server->on("/custom",handleRoute); 
}

void handleRoute(){
  Serial.println("[HTTP] handle route");
  wm.server->send(200, "text/plain", "hello from user code");
}

  wm.setWebServerCallback(bindServerCallback);

  std::vector<const char *> menu = {"wifi","wifinoscan","info","param","custom","close","sep","erase","update","restart","exit"};
  wm.setMenu(menu); // custom menu, pass vector

  // set custom html menu content, inside menu item custom
  const char* menuhtml = "<form action='/custom' method='get'><button>Custom</button></form><br/>\n";
  wm.setCustomMenuHTML(menuhtml);

I will work up an actual example
you can see it in action in the SUPER/ example already

Now if you want to do whatever on your external routes you can do anything you want there, or change the
const char R_root[] PROGMEM = "/";
to a custom page and make your own entire menu etc

<!-- gh-comment-id:1082335539 --> @tablatronix commented on GitHub (Mar 29, 2022): ok you could do it before, but you had to edit the strings code. You can still do it like that but I added a way to do it via code now. you will have to enable the custom menu item via `setMenu` put it where you want in the order. then set the custom menu item html ( can be many buttons or anything really ) The only issue is that you are limited to the one menu item, which CAN be contiguous buttons, so not a big deal as you can hack in html anyway to workaround it ) ```c++ void bindServerCallback(){ wm.server->on("/custom",handleRoute); } void handleRoute(){ Serial.println("[HTTP] handle route"); wm.server->send(200, "text/plain", "hello from user code"); } wm.setWebServerCallback(bindServerCallback); std::vector<const char *> menu = {"wifi","wifinoscan","info","param","custom","close","sep","erase","update","restart","exit"}; wm.setMenu(menu); // custom menu, pass vector // set custom html menu content, inside menu item custom const char* menuhtml = "<form action='/custom' method='get'><button>Custom</button></form><br/>\n"; wm.setCustomMenuHTML(menuhtml); ``` I will work up an actual example you can see it in action in the SUPER/ example already Now if you want to do whatever on your external routes you can do anything you want there, or change the const char R_root[] PROGMEM = "/"; to a custom page and make your own entire menu etc
Author
Owner

@zen85 commented on GitHub (Mar 30, 2022):

this is what i did and it works:

void handleLED()
{                                                       // If a POST request is made to URI /LED
  digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN)); // Change the state of the LED
  //server.sendHeader("Location", "/");       // Add a header to respond with a new location for the browser to go to the home page again
  //server.send(303);                         // Send it back to the browser with an HTTP status 303 (See Other) to redirect
}

void handleRoute()
{
  Serial.println("[HTTP] handle route Custom");
  wm.server->send(200, "text/html", "<iframe name=\"dummyframe\" id=\"dummyframe\" style=\"display: none;\"></iframe><form action=\"/LED\" target=\"dummyframe\" method=\"POST\"><input type=\"submit\" value=\"Toggle LED\"></form>");
}

void handleValues()
{
  Serial.println("[HTTP] handle route Values");
  wm.server->send(200, "text/html", "blabla");
}


void bindServerCallback()
{
  wm.server->on("/custom", handleRoute);
  wm.server->on("/values", handleValues);
  // wm.server->on("/info",handleRoute); // can override wm!
  wm.server->on("/LED", HTTP_POST, handleLED); // Call the 'handleLED' function when a POST request is made to URI "/LED"
}

and in strings_en.h

const char * const HTTP_PORTAL_MENU[] PROGMEM = {
"<form action='/wifi'    method='get'><button>Configure WiFi</button></form><br/>\n", // MENU_WIFI
"<form action='/0wifi'   method='get'><button>Configure WiFi (No Scan)</button></form><br/>\n", // MENU_WIFINOSCAN
"<form action='/custom'  method='get'><button>Custom</button></form><br/>\n", // MENU_CUSTOM
"<form action='/values'  method='get'><button>Values</button></form><br/>\n", // MENU_INFO
"<form action='/info'    method='get'><button>Info</button></form><br/>\n", // MENU_INFO
"<form action='/param'   method='get'><button>Setup</button></form><br/>\n",//MENU_PARAM
"<form action='/close'   method='get'><button>Close</button></form><br/>\n", // MENU_CLOSE
"<form action='/restart' method='get'><button>Restart</button></form><br/>\n",// MENU_RESTART
"<form action='/exit'    method='get'><button>Exit</button></form><br/>\n",  // MENU_EXIT
"<form action='/erase'   method='get'><button class='D'>Erase</button></form><br/>\n", // MENU_ERASE
"<form action='/update'  method='get'><button>Update</button></form><br/>\n",// MENU_UPDATE
"<hr><br/>" // MENU_SEP
};

what i did not manage to do:
I, for example, want to show analogue readings from pins on the /values page and i did not find a way to do that.
I found this way via dummyframe to toggle a pin via /custom though...

Can you think of an example where i can show dynamically readings from a sensor on a custom page?

<!-- gh-comment-id:1083427209 --> @zen85 commented on GitHub (Mar 30, 2022): this is what i did and it works: ```C++ void handleLED() { // If a POST request is made to URI /LED digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN)); // Change the state of the LED //server.sendHeader("Location", "/"); // Add a header to respond with a new location for the browser to go to the home page again //server.send(303); // Send it back to the browser with an HTTP status 303 (See Other) to redirect } void handleRoute() { Serial.println("[HTTP] handle route Custom"); wm.server->send(200, "text/html", "<iframe name=\"dummyframe\" id=\"dummyframe\" style=\"display: none;\"></iframe><form action=\"/LED\" target=\"dummyframe\" method=\"POST\"><input type=\"submit\" value=\"Toggle LED\"></form>"); } void handleValues() { Serial.println("[HTTP] handle route Values"); wm.server->send(200, "text/html", "blabla"); } void bindServerCallback() { wm.server->on("/custom", handleRoute); wm.server->on("/values", handleValues); // wm.server->on("/info",handleRoute); // can override wm! wm.server->on("/LED", HTTP_POST, handleLED); // Call the 'handleLED' function when a POST request is made to URI "/LED" } ``` and in strings_en.h ``` const char * const HTTP_PORTAL_MENU[] PROGMEM = { "<form action='/wifi' method='get'><button>Configure WiFi</button></form><br/>\n", // MENU_WIFI "<form action='/0wifi' method='get'><button>Configure WiFi (No Scan)</button></form><br/>\n", // MENU_WIFINOSCAN "<form action='/custom' method='get'><button>Custom</button></form><br/>\n", // MENU_CUSTOM "<form action='/values' method='get'><button>Values</button></form><br/>\n", // MENU_INFO "<form action='/info' method='get'><button>Info</button></form><br/>\n", // MENU_INFO "<form action='/param' method='get'><button>Setup</button></form><br/>\n",//MENU_PARAM "<form action='/close' method='get'><button>Close</button></form><br/>\n", // MENU_CLOSE "<form action='/restart' method='get'><button>Restart</button></form><br/>\n",// MENU_RESTART "<form action='/exit' method='get'><button>Exit</button></form><br/>\n", // MENU_EXIT "<form action='/erase' method='get'><button class='D'>Erase</button></form><br/>\n", // MENU_ERASE "<form action='/update' method='get'><button>Update</button></form><br/>\n",// MENU_UPDATE "<hr><br/>" // MENU_SEP }; ``` what i did not manage to do: I, for example, want to show analogue readings from pins on the /values page and i did not find a way to do that. I found this way via dummyframe to toggle a pin via /custom though... Can you think of an example where i can show dynamically readings from a sensor on a custom page?
Author
Owner

@tablatronix commented on GitHub (Mar 30, 2022):

Ahh i see, yeah you can also check serverargs for querystrings etc. You can probably get rid of the frame and use a button that does not have a target if you want to stay on the menu page on click. but thats just all html tricks

Yeah exactly , cept now you can just add the buttons via the customMenuHTML instead of strings.

for values, just add stuff to the html in

void handleValues()
{
  Serial.println("[HTTP] handle route Values");
  // generate html or ajax api, "<pre>".(String)analogRead(pin).</pre>" etc
  wm.server->send(200, "text/html", "blabla");
}
<!-- gh-comment-id:1083451618 --> @tablatronix commented on GitHub (Mar 30, 2022): Ahh i see, yeah you can also check serverargs for querystrings etc. You can probably get rid of the frame and use a button that does not have a target if you want to stay on the menu page on click. but thats just all html tricks Yeah exactly , cept now you can just add the buttons via the customMenuHTML instead of strings. for values, just add stuff to the html in ```C++ void handleValues() { Serial.println("[HTTP] handle route Values"); // generate html or ajax api, "<pre>".(String)analogRead(pin).</pre>" etc wm.server->send(200, "text/html", "blabla"); } ```
Author
Owner

@zen85 commented on GitHub (Apr 2, 2022):

that actually worked:

void handleValues()
{
  Serial.println("[HTTP] handle route Values");
  if (!loadValue()) {
    Serial.println("Failed to load config");
  } 
  else {
    Serial.println("Config loaded");
  }
  
  wm.server->send(200, "text/html", before1 + String(bootstrap) + String(before3) + String(before_value) + String(varname) + between_value + String(testwert) + after_value + String(before_value) + String(varname2) + between_value + String(testwert2) + after_value + after);

}


void bindServerCallback()
{

  wm.server->on("/values", handleValues);

}

the weird thing is, that it seems to reload the side about every 5 seconds on its own..

<!-- gh-comment-id:1086566545 --> @zen85 commented on GitHub (Apr 2, 2022): that actually worked: ``` void handleValues() { Serial.println("[HTTP] handle route Values"); if (!loadValue()) { Serial.println("Failed to load config"); } else { Serial.println("Config loaded"); } wm.server->send(200, "text/html", before1 + String(bootstrap) + String(before3) + String(before_value) + String(varname) + between_value + String(testwert) + after_value + String(before_value) + String(varname2) + between_value + String(testwert2) + after_value + after); } void bindServerCallback() { wm.server->on("/values", handleValues); } ``` the weird thing is, that it seems to reload the side about every 5 seconds on its own..
Author
Owner

@tablatronix commented on GitHub (Apr 2, 2022):

Thats odd

<!-- gh-comment-id:1086630560 --> @tablatronix commented on GitHub (Apr 2, 2022): Thats odd
Author
Owner

@zen85 commented on GitHub (Apr 3, 2022):

Thats odd

and completly my bad.... had <META http-equiv=refresh content=”5"> in my html by accident...

<!-- gh-comment-id:1086817357 --> @zen85 commented on GitHub (Apr 3, 2022): > Thats odd and completly my bad.... had <META http-equiv=refresh content=”5"> in my html by accident...
Author
Owner

@tablatronix commented on GitHub (Apr 7, 2022):

6a85acdf85

  • add an example
<!-- gh-comment-id:1091771114 --> @tablatronix commented on GitHub (Apr 7, 2022): 6a85acdf8531ca8745391d6b15cdd1130076acac - [ ] add an example
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/WiFiManager#1182
No description provided.