ESP8266 - I just can't understand this Client/Server stuff!

Hello all. Get ready to hate me :o

I have been playing around with an Adafruit Huzzah Feather ESP8266 module. Very nice.

I ma TRYING to get my head around clients, servers etc... it's happening slowly.

// DEMO V1
// Huzzah Feather ESP8266 module


#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
 
Adafruit_SSD1306 display = Adafruit_SSD1306(128, 32, &Wire);

const char *ssid = "Demo";                                                           //Set the network name
const char *password = "password";                                                  //Set the network password

float timer;

#define LED 14
#define BUTTON 12


ESP8266WebServer server(80);

//------------------------------------------------------------------------------
void setup() {
  
Serial.begin(115200);

// SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
display.begin(SSD1306_SWITCHCAPVCC, 0x3C); // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally + Address 0x3C for 128x32

pinMode(LED, OUTPUT);
pinMode(BUTTON,INPUT);
 
Serial.println("OLED begun");

display.clearDisplay();// Clear the buffer.
display.display();

delay(1000);

Serial.println();

Serial.println("Configuring access point...");


//WiFi.softAP(ssid, password, channel, hidden, max_connection)
WiFi.softAP(ssid, password, 1, false, 8);           // Channel = 1-13. Default is channel 1. 
                                                    // Hidden: True will hide ssid.  
                                                    // Max connection. Number of stations 0-8. Default is 4
                                                    // ip address default is 192.168.4.1

IPAddress local_IP(192,168,1,200);                  // Set our ip address
IPAddress gateway(192,168,4,200);
IPAddress subnet(255,255,255,0);

WiFi.softAPConfig(local_IP, gateway, subnet);       //Setup the network

IPAddress myIP = WiFi.softAPIP();

Serial.print("AP IP address: ");

Serial.println(myIP);

server.on("/", handleRoot);

server.begin();

Serial.println("HTTP server started");
Serial.println("");

  display.setTextSize(3);
  display.setTextColor(WHITE);
  display.drawRoundRect(0, 1, 128, 31, 4, WHITE);
  
  display.setCursor(2,6);
  display.print("TEST");
  display.display();
  delay(2000);
  
setup_main_page ();
  
Check_stations ();
}
//=====================================================================================
void loop() {
  
server.handleClient();

timer++;
  
if (timer>200000) {digitalWrite(LED, HIGH);Check_stations();timer=0;delay(50);digitalWrite(LED, LOW);}    //Check for new stations

if (digitalRead(BUTTON)==LOW) {
                         Serial.println("Button pressed");
                         server.send(200, "text/html", "<h1>Button on ESP8266 pressed</h1>");
                                                  
                         display.clearDisplay();
                         display.setTextSize(3);
                         display.setTextColor(WHITE);
                         display.setCursor(10,6);
                         display.print("BUTTON");
                         display.display();
                         delay(1500);
                         setup_main_page ();
                         
                         }

}
//=====================================================================================

void Check_stations (){

display.fillRect(114, 23, 128, 34, BLACK);                                                      //Clear the last digit

Serial.printf("Stations connected:= %d\n", WiFi.softAPgetStationNum());                //Display how many Stations are connected to the AP
  
  display.setCursor(115,24);
  display.print(WiFi.softAPgetStationNum());                                                    //Display how many Stations are connected to the AP
  display.display();
}

//-------------------------------------------------------------------------------------

void handleRoot() {

server.send(200, "text/html", "<h1>Welcome to Test network.  Broadcasting across Wiltshire using Huzzah Feather ESP8266. Version 2</h1>");   

}

//--------------------------------------------------------------------------------------

void setup_main_page (){
 
  display.clearDisplay();

  display.setTextSize(1);
  display.setCursor(0,0);
  display.println("Test is Broadcasting");
  display.setCursor(0,12);
  display.println("IP: 192.168.1.200");
  display.setCursor(0,24);
  display.println("STATIONS CONNECTED: ");
  display.display();

}

This code works. I can log into the webpage and see the text stating that its broadcasting across Wiltshire (well... 8 feet from my desk).

The Oled screen is for debugging - also working fine.
But, when you press the button, it serial.prints the fact that the button has been pressed, but does not send the message to the webpage using the line:

server.send(200, "text/html", "

Button on ESP8266 pressed

");

Why is that. What am I missing/doing wrong?

Thanks

But, when you press the button, it serial.prints the fact that the button has been pressed, but does not send the message to the webpage using the line:

Sure, because no client is requesting it at that time. The is no constant connection between the client and the server. The client asks the server for a web page and the server is answering that request. You told the server to send the page defined in handleRoot() (line 66) if a client is requesting a page.

I guessed that was the issue.

Really struggling to find a decent guide on how a webpage is served, operated etc.
Found various commands online for page auto-refresh etc, but i cannot seem to get them to work with this library.

Looks like I will just have to keep playing around and Googling until I get there.

Yea, this is beyond me.

Spent the whole day trying to wrap my head around how all this webpage stuff works.

The examples with the ESPWebServer-master library have absolutely no commenting at all which is really unhelpful.
What the heck is the point of an example if you don't explain what it does. If I could read it and work it out.... I would not need the example!

I have worked out the basics, but without guidance on how you actually control a page after it's initial creation is obviously way more involved than I thought.

You already have a handleRoot() routine. Why is that one just returning a fixed string? Try to return a different string (or even some calculated values) if conditions change. The easiest way to hold these conditions are global variables.

I spent the whole of last night learning the basics of HTTP and webpages. I have a slightly better understanding of the whole process now (but not by much!)

I have managed to get the routine to auto - update the page every second, and now I am trying to get it to only update the variable using Ajax.

So, if I understand correctly, I basically need to design a webpage and fire that over to the client upon initial connection using the HandleRoot(), and then any changes at my ESP8266 end get fired over to the page again, where I update my variable/s.

Or, if the user on the webpage does something, then in my server code I have a on.server routine setup for that reply... eg server.on("/Button", {}

I feel your pain! a universal law of understanding is that is you do not know what the words mean, you cannot understand what the people are saying. there are so many assumptions that you already know what the writer is talking about that is is very hard to wrap your head around this part of this hobby.

this guy has done a great job of putting things in a decent sequence.
[Beginners Guide](https://tttapa.github.io/ESP8266/Chap01 - ESP8266.html)

If I understand what Pylon was saying, you get your data and it is on your server,
if no one asks it does not send it
if you have a second device with a constant link, it updates continuously.

That is a good link. I will add it to the huge folder of pages I have already bookmarked!

My problem is, I simply don't understand the different types of formatting to get the result I need.
Plus, I think the particular library I am using is not exactly standard.

For instance...

snprintf ( temp, 800,

"<html>\                                                                                        
  <head>\
    <meta http-equiv='refresh' content='10'/>\                                                                                                                                
    <title>Steves first website disaster</title>\
    <style>\
      body { background-color: rgb(0, 0, 0); font-family: Arial, Helvetica, Sans-Serif; Color: rgb(255, 255, 255); }\         
    </style>\
  </head>\
  <body>\    
    <h1>Welcome to Steve net.</h1>\
    <h2>Broadcasting using Huzzah Feather ESP8266.</h1>\
    <h2>Version 3</h1>\
    <h3>Current monitored equipment</h3>\
    <p>Time online: %02d:%02d:%02d</p>\  
    <p><p>\
    </style>Color: rgb(100, 100, 100);</style>\ 
    <p>Tank 1:   + String(analogRead(A0))</p>\
    <p>Tank 2:   + String(analogRead(A1))</p>\
    <p>Tank 3:   + String(analogRead(A2))</p>\
    <p>Tank 4:   + String(analogRead(A3))</p>\                                                                                             
  </body>\
</html>",

This code is a butchered version of the snippets I have found in the examples. I assume the 800 is the string length (is there a maximum?).
Surely I do not need to set a string length long enough to fit an entire webpage in?

The line with rgb 100,100,100 doesn't work.
It prints the Tank 1, Tank 2 etc, but then prints the text String(analogRead(A0)) rather than the result.

All examples of writing to a webpage have the text in " or '. If I add those in, it fails to compile.
I think that maybe an arduino thing?

Is there a better way of setting up the webpage in the first place, rather than using this string method.

Frying my brain with little progress this

Can someone explain if I can do this....

server.send(200, "text/html", index.htm);

And then assemble my webpage as a document in my project directory and send it that way (That line above doesn't compile - just a guess).

I am really struggling here with the fact that this ESP8266 server library is using a string to upload all the contents of the webpage.
It's messing up all the formatting compared to the examples you find online.

This code is a butchered version of the snippets I have found in the examples. I assume the 800 is the string length (is there a maximum?).

No, it's the size in the buffer named "temp", so it's the maximum length the resulting string may have that is written to that buffer.

Surely I do not need to set a string length long enough to fit an entire webpage in?

Why is that so sure? It depends on how you structure your program. If you put the complete weg page into one byte array it's better to know the size.

It prints the Tank 1, Tank 2 etc, but then prints the text String(analogRead(A0)) rather than the result.

Sure, that's what you wrote into that string.

I believe you should start with basic programming examples and not trying to send out complete web pages as the first lesson. Learn to program the simple stuff and add one thing at a time.

Can someone explain if I can do this....

server.send(200, "text/html", index.htm);

No, index.html doesn't correctly name a variable (the dot is not allowed in variable names). It might be that you meant something completely different but you didn't tell us what you tried to do with this line of code.

And then assemble my webpage as a document in my project directory and send it that way (That line above doesn't compile - just a guess).

You cannot send a document, you can send only a sketch. An microcontroller like the ESP8266 isn't predestined to serve complete web sites. It may provide some easy HTML code around results of sensor readings but if you want a full-fledged web site it's better to serve is from a real web server and let the ESP send it's results to that web server instead.

pylon:
You cannot send a document, you can send only a sketch. An microcontroller like the ESP8266 isn't predestined to serve complete web sites. It may provide some easy HTML code around results of sensor readings but if you want a full-fledged web site it's better to serve is from a real web server and let the ESP send it's results to that web server instead.

a MCU can serve web files from SD card or SPIFFS. for esp8266 SPIFFS is a file system solution. see the FSBrowser example of the ESP8266WebServer library

I have been looking into the SPIFFS angle.

I understand the principle of sending the webpage. I know you are not sending a document.
On a project a while back, I did get it to load the basic webpage from an SD card. But I don't want an SD card on this project.

I thought maybe I could lift the same data from a file on my pc, rather than the SD card.

The code I have at the moment is sending the string data to the webpage.
My problem is the formatting... I have to try 30 different methods and layout until I hit one that works.
Also, I have a line of text that says "Input 1:" for instance. I need to follow that with the actual value reported from the sensor.
How do you do that in a string? As soon as I end the string to add the variable to the end, I cannot work out how to add further text to the string before its sent.

"<html>\                                                                                        
  <head>\
    <meta http-equiv='refresh' content='1'/>\                                                                                                                                
    <title>Test page</title>\
    <style>\
      body { background-color: rgb(0, 0, 0); font-family: Arial, Helvetica, Sans-Serif; Color: rgb(255, 255, 255); }\         
    </style>\
  </head>\
  <body>\   
    <h1>Test page.</h1>\
    <h2>Broadcasting using Huzzah Feather ESP8266.</h1>\
    <h2>Version 3</h1>\
    <p style='color:rgb(0, 150, 150);'\
    <p>Time online: %02d:%02d:%02d</p>\  
    <h3>Current monitored equipment:</h3>\ 
    
\
    <p style='color:rgb(0, 150, 0);'\
    <p>Water level in tank 1:   + String(analogRead(A0))</p>\
    <p style='color:rgb(0, 150, 0);'\
    <p>Water level in tank 2:   + String(analogRead(A1))</p>\
    <p style='color:rgb(0, 150, 0);'\
    <p>Water level in tank 3:   + String(analogRead(A2))</p>\
    <p style='color:rgb(0, 150, 0);'\
    <p>Water level in tank 4:   + String(analogRead(A3))</p>\                                                                                             
  </body>\
</html>",

I had to state the color for the text 4 times for the water tanks. Why does it not remember the text color after the first statement?

And, how do I get the analogue data to show?

It is very good that people upload guides to various functions, tricks etc with Arduinos, ESP8266's etc
I have been reading A Beginner's Guide to the ESP8266.

A beginners guide to the ESP8266. Well written, and explains a lot.
But... they is ALWAYS some vital bit missing. Nowhere in that document does is say you have to install a SPIFFS uploader to a specific directory in the Arduino IDE.

An hours Googling later... and I finally get that part working.
Is's so frustrating to try and wrap your head around this stuff, but have little snippets missed out, or they assume you know parts that I don't.

I am not that clever with this stuff. I want to learn it, and I have been 4 days trying to get a madly simple project off the ground.

I thank the people that try to help, and take the time to assist people and write these guides...
But please read it through, and don't assume that we know anything!