Webpage Code in Separate Header File

All,

I hope you can help. I am attempting to follow a tutorial of how to include webpage code in a separate header file (ESP8266 Web Server with HTML Web Page | Circuits4you.com). I am using a D1 mini for this tutorial.

I created the index.h and the Web_Server.ino files as described below:

index.h

const char MAIN_page[] PROGMEM = R"=====(
<HTML>
	<HEAD>
			<TITLE>My first web page</TITLE>
	</HEAD>
<BODY>
	<CENTER>
			<B>Hello World.... </B>
	</CENTER>	
</BODY>
</HTML>
)=====";

Web_Server.ino

/*
 * Hello world web server
 * circuits4you.com
 */
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>

#include "index.h" //Our HTML webpage contents

//SSID and Password of your WiFi router
const char* ssid = "Router";
const char* password = "123456789";

ESP8266WebServer server(80); //Server on port 80

//===============================================================
// This routine is executed when you open its IP in browser
//===============================================================
void handleRoot() {
 String s = MAIN_page; //Read HTML contents
 server.send(200, "text/html", s); //Send web page
}
//==============================================================
//                  SETUP
//==============================================================
void setup(void){
  Serial.begin(9600);
  
  WiFi.begin(ssid, password);     //Connect to your WiFi router
  Serial.println("");

  // Wait for connection
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  //If connection successful show IP address in serial monitor
  Serial.println("");
  Serial.print("Connected to ");
  Serial.println(ssid);
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());  //IP address assigned to your ESP
 
  server.on("/", handleRoot);      //Which routine to handle at root location

  server.begin();                  //Start server
  Serial.println("HTTP server started");
}
//==============================================================
//                     LOOP
//==============================================================
void loop(void){
  server.handleClient();          //Handle client requests
}

I think there is something going on using the header file as a webpage and was hoping you all had some thoughts. This is the first time I ever ran into this type of issue.

Here is the error I am getting on the output:

20:16:24.694 -> IP address: 192.168.1.21
20:16:24.740 -> HTTP server started
20:16:28.490 -> 
20:16:28.490 -> Exception (3):
20:16:28.490 -> epc1=0x4000bf64 epc2=0x00000000 epc3=0x00000000 excvaddr=0x4023d00d depc=0x00000000
20:16:28.584 -> 
20:16:28.584 -> >>>stack>>>
20:16:28.584 -> 
20:16:28.584 -> ctx: cont
20:16:28.584 -> sp: 3ffffd00 end: 3fffffc0 offset: 01a0
20:16:28.678 -> 3ffffea0:  74736f00 00000001 3ffef824 40203192  
20:16:28.678 -> 3ffffeb0:  3ffffe00 3ffef84c 80000000 40205cb8  
20:16:28.772 -> 3ffffec0:  00000001 4020107c 3ffffef0 40207dde  
20:16:28.819 -> 3ffffed0:  00000001 4020107c 3ffef824 401000e1  
20:16:28.865 -> 3ffffee0:  3ffef824 3ffee398 3ffef824 40201b8e  
20:16:28.912 -> 3ffffef0:  3ffe0000 3fff0000 80fee4f0 80000030  
20:16:28.959 -> 3fffff00:  3ffef824 3ffee398 3ffee358 402031e6  
20:16:29.006 -> 3fffff10:  0000002f 80000000 81fefb00 0000005f  
20:16:29.053 -> 3fffff20:  80005054 8eb7f24b 40100200 0000200d  
20:16:29.100 -> 3fffff30:  00000001 3ffee398 00000001 40100170  
20:16:29.147 -> 3fffff40:  00000001 00000000 3ffee358 3ffee4f0  
20:16:29.194 -> 3fffff50:  00000001 3ffee37c 3ffee358 3ffee4f0  
20:16:29.240 -> 3fffff60:  00000001 3ffee37c 3ffee358 4020347b  
20:16:29.334 -> 3fffff70:  00000000 00000000 00001388 feefeffe  
20:16:29.381 -> 3fffff80:  00000000 00000000 00000001 40100170  
20:16:29.428 -> 3fffff90:  3fffdad0 00000000 3ffee4b0 4020351c  
20:16:29.475 -> 3fffffa0:  3fffdad0 00000000 3ffee4b0 40206558  
20:16:29.522 -> 3fffffb0:  feefeffe feefeffe 3ffe84f0 40100bb1  
20:16:29.569 -> <<<stack<<<

Thanks in advance,

MT

I tried the example code on that site and it causes my wemos 8266 to crash when the header file is called. The /ledOff and /ledOn part works to operate the board LED.

Try using the EspExceptionDecoder tool to see if it will give you some useful information about the problem:

pert:
Try using the EspExceptionDecoder tool to see if it will give you some useful information about the problem:
GitHub - me-no-dev/EspExceptionDecoder: Exception Stack Trace Decoder for ESP8266 and ESP32

I will try and post the results here . Thanks for your help.

MT

String s = MAIN_page; //Read HTML contents

Why? The String looks like a very expensive and unnecessary copy. Just pass MAIN_page to the send function directly.

const char MAIN_page[] PROGMEM = R"=====(

The PROGMEM attribute is not a part of the type of MAIN_page. This could cause the compiler to select the wrong overload of the String constructor (String s = MAIN_page). Reading data from PROGMEM requires different instructions than reading data from RAM, where ordinary strings reside.
However, since Sep 14, 2019, this shouldn't be an issue anymore.
What version of the ESP8266 Core are you using?

You could try declaring the MAIN_page variable with the correct type, so that String selects the right overload, or you could try passing it to the send function directly (it'll always use the PROGMEM function if you pass a const char *).

[color=#5e6d03]#define[/color] [color=#000000]FLASH_STR[/color][color=#000000]([/color][color=#000000]x[/color][color=#000000])[/color] [color=#000000][[/color][color=#000000]][/color] [color=#000000]{[/color] [color=#000000]\[/color]
  [color=#00979c]const[/color] [color=#00979c]static[/color] [color=#00979c]char[/color] [color=#000000]str[/color][color=#000000][[/color][color=#000000]][/color] [color=#00979c]PROGMEM[/color] [color=#434f54]=[/color] [color=#000000]([/color][color=#000000]x[/color][color=#000000])[/color][color=#000000];[/color][color=#000000]\[/color]
  [color=#5e6d03]return[/color] [color=#00979c]reinterpret_cast[/color][color=#434f54]<[/color][color=#00979c]const[/color] [color=#000000]__FlashStringHelper[/color] [color=#434f54]*[/color][color=#434f54]>[/color][color=#000000]([/color][color=#000000]str[/color][color=#000000])[/color][color=#000000];[/color] [color=#000000]}[/color][color=#000000]([/color][color=#000000])[/color]

[color=#00979c]const[/color] [color=#00979c]auto[/color] [color=#000000]MAIN_page[/color] [color=#434f54]=[/color] [color=#000000]FLASH_STR[/color][color=#000000]([/color][color=#000000]R[/color][color=#000000]"====([/color]
[color=#434f54]<[/color][color=#000000]HTML[/color][color=#434f54]>[/color]
  [color=#434f54]<[/color][color=#000000]HEAD[/color][color=#434f54]>[/color]
      [color=#434f54]<[/color][color=#000000]TITLE[/color][color=#434f54]>[/color][color=#000000]My[/color] [color=#000000]first[/color] [color=#000000]web[/color] [color=#000000]page[/color][color=#434f54]<[/color][color=#434f54]/[/color][color=#000000]TITLE[/color][color=#434f54]>[/color]
  [color=#434f54]<[/color][color=#434f54]/[/color][color=#000000]HEAD[/color][color=#434f54]>[/color]
[color=#434f54]<[/color][color=#000000]BODY[/color][color=#434f54]>[/color]
  [color=#434f54]<[/color][color=#000000]CENTER[/color][color=#434f54]>[/color]
      [color=#434f54]<[/color][color=#000000]B[/color][color=#434f54]>[/color][color=#000000]Hello[/color] [color=#000000]World[/color][color=#434f54].[/color][color=#434f54].[/color][color=#434f54].[/color][color=#434f54].[/color] [color=#434f54]<[/color][color=#434f54]/[/color][color=#000000]B[/color][color=#434f54]>[/color]
  [color=#434f54]<[/color][color=#434f54]/[/color][color=#000000]CENTER[/color][color=#434f54]>[/color] 
[color=#434f54]<[/color][color=#434f54]/[/color][color=#000000]BODY[/color][color=#434f54]>[/color]
[color=#434f54]<[/color][color=#434f54]/[/color][color=#000000]HTML[/color][color=#434f54]>[/color]
[color=#000000])[/color][color=#434f54]==[/color][color=#434f54]==[/color][color=#000000]");[/color]

Pieter

mt_keg:
I am attempting to follow a tutorial of how to include webpage code in a separate header file

Generally speaking, that's a bad idea. Neither variable definitions nor executable code belong in header files. Reason being is that if that header file get #include(d) in multiple .ino / .cpp files, you'll get linker errors for duplicate definitions. For guidance on what belongs in header files version source code files, see Reply #3 Here.

Was there a solution to this issue?
Arduino 1.8.10
ESP Exception Decoder output,

Decoding stack results
0x4020671f: String::String(char const*) at /home/amf/.arduino15/packages/esp8266/hardware/esp8266/2.7.1/cores/esp8266/WString.cpp line 34
0x40203f6c: handleRoot() at /home/amf/devel/esp3266/wemos/projects/webserver/webserver.ino line 25
0x40201eb4: esp8266webserver::FunctionRequestHandler ::handle(esp8266webserver::ESP8266WebServerTemplate &, HTTPMethod, String) at /home/amf/.arduino15/packages/esp8266/hardware/esp8266/2.7.1/libraries/ESP8266WebServer/src/detail/RequestHandlersImpl.h line 42
0x402092b4: esp8266webserver::FunctionRequestHandler ::canHandle(HTTPMethod, String) at /home/amf/.arduino15/packages/esp8266/hardware/esp8266/2.7.1/libraries/ESP8266WebServer/src/detail/RequestHandlersImpl.h line 28
0x40209282: std::_Function_handler ::_M_invoke(std::_Any_data const&) at /home/amf/.arduino15/packages/esp8266/tools/xtensa-lx106-elf-gcc/2.5.0-4-b40a506/xtensa-lx106-elf/include/c++/4.8.2/functional line 2073
0x401000e1: std::function ::operator()() const at /home/amf/.arduino15/packages/esp8266/tools/xtensa-lx106-elf-gcc/2.5.0-4-b40a506/xtensa-lx106-elf/include/c++/4.8.2/functional line 2465
0x40201ef0: esp8266webserver::FunctionRequestHandler ::handle(esp8266webserver::ESP8266WebServerTemplate &, HTTPMethod, String) at /home/amf/.arduino15/packages/esp8266/hardware/esp8266/2.7.1/libraries/ESP8266WebServer/src/detail/RequestHandlersImpl.h line 48
0x40203fe2: esp8266webserver::ESP8266WebServerTemplate ::_handleRequest() at /home/amf/.arduino15/packages/esp8266/hardware/esp8266/2.7.1/libraries/ESP8266WebServer/src/ESP8266WebServer-impl.h line 673
0x402092b4: esp8266webserver::FunctionRequestHandler ::canHandle(HTTPMethod, String) at /home/amf/.arduino15/packages/esp8266/hardware/esp8266/2.7.1/libraries/ESP8266WebServer/src/detail/RequestHandlersImpl.h line 28
0x402043b8: esp8266webserver::ESP8266WebServerTemplate ::handleClient() at /home/amf/.arduino15/packages/esp8266/hardware/esp8266/2.7.1/libraries/ESP8266WebServer/src/ESP8266WebServer-impl.h line 335
0x40209278: std::_Function_handler ::_M_invoke(std::_Any_data const&) at /home/amf/.arduino15/packages/esp8266/tools/xtensa-lx106-elf-gcc/2.5.0-4-b40a506/xtensa-lx106-elf/include/c++/4.8.2/functional line 2069
0x40100170: ets_post(uint8, ETSSignal, ETSParam) at /home/amf/.arduino15/packages/esp8266/hardware/esp8266/2.7.1/cores/esp8266/core_esp8266_main.cpp line 177
0x4020447c: loop() at /home/amf/devel/esp3266/wemos/projects/webserver/webserver.ino line 73
0x40207700: loop_wrapper() at /home/amf/.arduino15/packages/esp8266/hardware/esp8266/2.7.1/cores/esp8266/core_esp8266_main.cpp line 197

Also tested it with Arduino 1.8.13, same issue

Post your code.

The version of the Arduino IDE is irrelevant here, it's just the version of the text editor. The version of the ESP8266 Core is what matters.

I'm using the same example as the original poster, the following fixed the issue. (after much googling)
String s = FPSTR(MAIN_page);

Why "after much googling"? That's effectively the same solution as the one I posted in reply #4.
Like I mentioned in that same reply, converting it to a String before calling the send function is extremely wasteful and useless. Pass MAIN_page to the send function directly.

I tried the FLASH_STR macro, it would not compile. Anyway, if others have issues, maybe what I posted will help.
Thanks,

I will try to test it too. I am just trying to learn to code. I am working with one project and we use one of the seo tools, which may help you. We tried it first to count the number of web pages on the sites, but we use more it's options now. If I am not wrong it may help with some code issues too, check it as this tool is for free.