Update:
This is a very old guide and things have moved on a lot since this was written. One of the main advances is the ESP8266 core for the Arduino IDE. This means the ESP8266 can now be programmed like an Arduino and this is how I use them now, no more messing around with AT commands. For a general overview and examples of using the ESP8266 with the Arduino core see ESP8266 and the Arduino IDE.
Here is my first attempt at a web server using the ESP8266. It includes a request count and also a text input field.
Enter your name and hit submit
The code is not very elegant and it can be made far more efficient. At present there are no checks to see if the command issued to the ESP8266 is successful or not. Ideally, each command should be checked to see if a “busy” reply has been received and if so, the command resent.
If a cipsend command is incorrect or not successful, the ESP8266 waits for the command to be completed and any subsequent commands will get a busy reply. The only way I have found to get out of this is a hard reset. In a future version I will connect the ESP8266 reset to the Arduino so I can control is from software.
The module is not as quick as I expected and I often get busy replies. To counter this I have used 2 second delays on each command but sometimes this is still not enough.
Another issue, I sometimes get extra messages from the ESP8266 after the page has been sent. I know absolutely nothing about http and don’t know where these come from. I haven’t had time to look in to this and for now I have added extra getReply()s at the end of the code to absorb any extra messages.
Commands Used
Remember that the ESP8266 expects all AT commands to end with the carriage return and newline characters (\r\n).
AT+CWMODE=1
The Esp8266 has three modes:
- Station Mode (ST). The ESP8266 acts as a wifi device & can connect to a network / Access Point.
- Access Point Mode (AP). The ESP8266 becomes the network (AP) and other devices can connect to it.
- ST & AP Mode. The ESP8288 is both an AP and a station at the same time. In this mode the ESP8266 will have 2 ip addresses.
In the example below I am using Station Mode which is entered with the command AT+CWMODE=1
AT+CWJAP=”NetworkSSID”,”password”
AT+CWJAP is used to join a network. NetworkSSID is the name of the network and password is the password.
AT+CIFSR
AT+CIFSR returns the ip address of the ESP8266. In the example below this is assigned by the router when it joins the network.
AT+CIPMUX=1
AT+CIPMUX=1 tells the ESP8266 to allow multiple connections. This is required when using as a server.
AT+CIPSERVER
AT+CIPSERVER=1,80 starts a server on port 80. Port 80 is the normal port for web pages.
AT+CIPSEND
CIPSEND is used to send data to the ESP8266. AT+CIPSEND=0,25 tells the module to expect 25 characters using channel id 0.
After sending this command you then need to send the html data, for example espSerial.print(“
AT+CIPCLOSE
AT+CIPCLOSE=0 closes the connection.
Code
You can download the sketch at the bottom of the page.
You will need to change the network settings to suit your own network
Change the following line:
espSerial.print("AT+CWJAP=\"myNetworkSSID\",\"password\"\r\n"); |
// Basic Arduino & ESP8266 webserver // // uses AltSoftSerial download from https://www.pjrc.com/teensy/td_libs_AltSoftSerial.html // this can be replaced with the normal software serial #include <AltSoftSerial.h> // Arduino pin 08 for RX // Arduino Pin 09 for TX AltSoftSerial espSerial; const bool printReply = true; const char line[] = "-----\n\r"; int loopCount=0; char html[50]; char command[20]; char reply[500]; // you wouldn't normally do this char ipAddress [20]; char name[30]; int lenHtml = 0; char temp[5]; void setup() { Serial.begin(9600); Serial.println("Start\r\n\r\n"); espSerial.begin(9600); // your ESP8266 module's baud rate might be different // reset the ESP8266 Serial.println("reset the module"); espSerial.print("AT+RST\r\n"); getReply( 2000 ); // configure as a station Serial.println("Change to station mode"); espSerial.print("AT+CWMODE=1\r\n"); getReply( 1500 ); // connect to the network. Uses DHCP. ip will be assigned by the router. Serial.println("Connect to a network "); // Enter the SSID and password for your own network espSerial.print("AT+CWJAP=\"myNetworkSSID\",\"password\"\r\n"); getReply( 6000 ); // get ip address Serial.println("Get the ip address assigned ny the router"); espSerial.print("AT+CIFSR\r\n"); getReply( 1000 ); // parse ip address. int len = strlen( reply ); bool done=false; bool error = false; int pos = 0; while (!done) { if ( reply[pos] == 10) { done = true;} pos++; if (pos > len) { done = true; error = true;} } if (!error) { int buffpos = 0; done = false; while (!done) { if ( reply[pos] == 13 ) { done = true; } else { ipAddress[buffpos] = reply[pos]; buffpos++; pos++; } } ipAddress[buffpos] = 0; } else { strcpy(ipAddress,"ERROR"); } // configure for multiple connections Serial.println("Set for multiple connections"); espSerial.print("AT+CIPMUX=1\r\n"); getReply( 1500 ); // start server on port 80 Serial.println("Start the server"); espSerial.print("AT+CIPSERVER=1,80\r\n"); getReply( 1500 ); Serial.println(""); Serial.println("Waiting for page request"); Serial.print("Connect to "); Serial.println(ipAddress); Serial.println(""); } void loop() { if(espSerial.available()) // check if the ESP8266 is sending data { // this is the +IPD reply - it is quite long. // normally you would not need to copy the whole message in to a variable you can copy up to "HOST" only // or you can just search the data character by character as you read the serial port. getReply( 2000 ); bool foundIPD = false; for (int i=0; i<strlen(reply); i++) { if ( (reply[i]=='I') && (reply[i+1]=='P') && (reply[i+2]=='D') ) { foundIPD = true; } } if ( foundIPD ) { loopCount++; // Serial.print( "Have a request. Loop = "); Serial.println(loopCount); Serial.println(""); // check to see if we have a name - look for name= bool haveName = false; int nameStartPos = 0; for (int i=0; i<strlen(reply); i++) { if (!haveName) // just get the first occurrence of name { if ( (reply[i]=='n') && (reply[i+1]=='a') && (reply[i+2]=='m') && (reply[i+3]=='e') && (reply[i+4]=='=') ) { haveName = true; nameStartPos = i+5; } } } // get the name - copy everything from nameStartPos to the first space character if (haveName) { int tempPos = 0; bool finishedCopying = false; for (int i=nameStartPos; i<strlen(reply); i++) { if ( (reply[i]==' ') && !finishedCopying ) { finishedCopying = true; } if ( !finishedCopying ) { name[tempPos] = reply[i]; tempPos++; } } name[tempPos] = 0; } if (haveName) { Serial.print( "name = "); Serial.println(name); Serial.println(""); } else { Serial.println( "no name entered"); Serial.println(""); } // start sending the HTML strcpy(html,"<html><head></head><body>"); strcpy(command,"AT+CIPSEND=0,25\r\n"); espSerial.print(command); getReply( 2000 ); espSerial.print(html); getReply( 2000 ); strcpy(html,"<h1>ESP8266 Webserver</h1>"); strcpy(command,"AT+CIPSEND=0,26\r\n"); espSerial.print(command); getReply( 2000 ); espSerial.print(html); getReply( 2000 ); strcpy(html,"<p>Served by Arduino and ESP8266</p>"); strcpy(command,"AT+CIPSEND=0,36\r\n"); espSerial.print(command); getReply( 2000 ); espSerial.print(html); getReply( 2000 ); strcpy(html,"<p>Request number "); itoa( loopCount, temp, 10); strcat(html,temp); strcat(html,"</p>"); // need the length of html int lenHtml = strlen( html ); strcpy(command,"AT+CIPSEND=0,"); itoa( lenHtml, temp, 10); strcat(command, temp); strcat(command, "\r\n"); espSerial.print(command); getReply( 2000 ); espSerial.print(html); getReply( 2000 ); if (haveName) { // write name strcpy(html,"<p>Your name is "); strcat(html, name ); strcat(html,"</p>"); // need the length of html for the cipsend command lenHtml = strlen( html ); strcpy(command,"AT+CIPSEND=0,"); itoa( lenHtml, temp, 10); strcat(command, temp); strcat(command, "\r\n"); espSerial.print(command); getReply( 2000 ); espSerial.print(html); getReply( 2000 ); } strcpy(html,"<form action=\""); strcat(html, ipAddress); strcat(html, "\" method=\"GET\">"); strcat(command, "\r\n"); lenHtml = strlen( html ); itoa( lenHtml, temp, 10); strcpy(command,"AT+CIPSEND=0,"); itoa( lenHtml, temp, 10); strcat(command, temp); strcat(command, "\r\n"); espSerial.print(command); getReply( 2000 ); espSerial.print(html); getReply( 2000 ); strcpy(html,"Name:<br><input type=\"text\" name=\"name\">"); strcpy(command,"AT+CIPSEND=0,40\r\n"); espSerial.print(command); getReply( 2000 ); espSerial.print(html); getReply( 2000 ); strcpy(html,"<input type=\"submit\" value=\"Submit\"></form>"); strcpy(command,"AT+CIPSEND=0,43\r\n"); espSerial.print(command); getReply( 2000 ); espSerial.print(html); getReply( 2000 ); strcpy(html,"</body></html>"); strcpy(command,"AT+CIPSEND=0,14\r\n"); espSerial.print(command); getReply( 2000 ); espSerial.print(html); getReply( 2000 ); // close the connection espSerial.print( "AT+CIPCLOSE=0\r\n" ); getReply( 1500 ); Serial.println("last getReply 1 "); getReply( 1500 ); Serial.println("last getReply 2 "); getReply( 1500 ); } // if(espSerial.find("+IPD")) } //if(espSerial.available()) delay (100); // drop to here and wait for next request. } void getReply(int wait) { int tempPos = 0; long int time = millis(); while( (time + wait) > millis()) { while(espSerial.available()) { char c = espSerial.read(); if (tempPos < 500) { reply[tempPos] = c; tempPos++; } } reply[tempPos] = 0; } if (printReply) { Serial.println( reply ); Serial.println(line); } } |
Serial Monitor Output
The output in the serial monitor looks like this:
Start reset the module AT+RST OK ÍÅÛÔÕtùnq!Åý9Åüÿ [System Ready, Vendor:www.ai-thinker.com] ----- Change to station mode AT+CWMODE=1 no change ----- Connect to a network AT+CWJAP="myNetworkSSID","password" OK ----- Get the ip address assigned ny the router AT+CIFSR 192.168.2.108 OK ----- Set for multiple connections AT+CIPMUX=1 OK ----- Start the server AT+CIPSERVER=1,80 OK ----- Waiting for page request Connect to 192.168.2.108 Link +IPD,0,308:GET /192.168.2.108 HTTP/1.1 Host: 192.168.2.108 User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:34.0) Gecko/20100101 Firefox/34.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate DNT: 1 Connection: keep-alive OK ----- no name entered AT+CIPSEND=0,25 > Link ----- <html><head></head><body> SEND OK ----- AT+CIPSEND=0,26 > ----- <h1>ESP8266 Webserver</h1> SEND OK ----- AT+CIPSEND=0,36 > ----- <p>Served by Arduino and ESP8266</p> SEND OK ----- AT+CIPSEND=0,23 > ----- <p>Request number 1</p> SEND OK ----- AT+CIPSEND=0,42 > ----- <form action="192.168.2.108" method="GET"> SEND OK ----- AT+CIPSEND=0,40 > ----- Name:<br><input type="text" name="name"> SEND OK ----- AT+CIPSEND=0,43 > ----- <input type="submit" value="Submit"></form> SEND OK ----- AT+CIPSEND=0,14 > ----- </body></html> SEND OK ----- AT+CIPCLOSE=0 OK Unlink ----- last getReply 1 ----- last getReply 2 ----- |
Download
I had a typo in the original sketch; AltSoftSerial uses the Arduino pins 8 and 9 (not 9 and 10). Pin 8 is Rx and pin 9 is Tx. I have updated the sketch.
Hi,
Great job, it work on my arduino pro mini.
This is the most detailed tuto i found on the web.
thanks
Glad it was helpful.
Does the ABC work with a BlueSMiRF RN-41 module & Arduino Mega?
If not, is their a way to adapt it to?
I have copied your comment to the Arduino Bluetooth Control page. https://www.martyncurrey.com/arduino-bluetooth-control/
Hi! Thanks for the tutorial. Would anyone give me a hint how to use two serials at the same time?
The above sketch uses 2 serials; hardware serial to talk to a host PC and the serial monitor and AltSoftSerial to talk to the ESP8266 module. AltSoftSerial has the pins hardwired to D8 and D9 (there was a typo in the above sketch, Arduino D9 is TX and D8 is RX. Arduino TX goes to ESP8266 RX and Arduino RX goes to ESP8266 TX.
Remember the ESP8266 is 3.3V and you should use a voltage divider on the Arduino TX line. Arduino RX can be connected directly to the ESP8266 TX pin. See https://www.martyncurrey.com/?p=1475 for a diagram.
You can also use the regular SoftwareSerial which allows you to select which pins you want to use. See https://www.martyncurrey.com/?p=1475 for an example.
Thank you! It all started making sense now. Very much appreciated!
Also, I’m very curious to see your circuit.
Have a look at https://www.martyncurrey.com/?p=1475
Thanks!
Thanks a lot for that well structured and very good example.
Hi…it’s just marvelous job!!
but one problem is ….i have used this code to show the text to lcd.i’ve done it!!but it can’t print special characters…i:e: it prints ‘+’ sign instead of space…if i send name like “tom brian” in the webserver text box ..it prints “tom+brian”…could u please help…to get rid of it>>.
When you send text the spaces are used as separators and replaced with the “+” character. You would need to manual change them back; search name for the “+” and change to a space.
could u please help me with the code…it will be so kind of u.
Hi,
all you need to do is check for the “+” when copying the name and change it to a space.
if (haveName)
{
int tempPos = 0;
bool finishedCopying = false;
for (int i=nameStartPos; i<strlen(reply); i++)
{
if ( (reply[i]==’ ‘) && !finishedCopying )
{ finishedCopying = true; }
if ( !finishedCopying )
{
if (name[tempPos] == ‘+’) { name[tempPos] = ‘ ‘ }
name[tempPos] = reply[i];
tempPos++;
}
}
name[tempPos] = 0;
}
*The above has not been tested.
thanks …but it’s not working
sorry, there’s a typo.
try:
if (reply[i] == ‘+’) { name[tempPos] = ‘ ‘ } else { name[tempPos] = reply[i]; }
Thanks a lot …it’s working…but special characters shows like that.i:e: (for ‘ ! ‘ it shows ‘ %21′ ).
i;ve tried it in this way
if (reply[i] ==’%21′) { name[tempPos] =’!’;}
else{name[tempPos] = reply[i];}
——-it’s not working.
2ndly
if (reply[i] ==’%’&&’2’&&’1′) { name[tempPos] =’!’;}
else{name[tempPos] = reply[i];}
3rdly
if ((reply[i] ==’%’)&&(reply[i+1]=’2′)&&reply[i+2]=’1′) { name[tempPos] =’!’;}
else{name[tempPos] = reply[i];}
In the 2nd & 3rd attempts it shows ‘!21’ whether i want to show only ‘!’
thanks again for great help
This looks to be an issue with how the characters are encoded on the website although they display OK for me.
You can also use the ascii value of the character. For example the plus sign is character 43 so you can use if (reply[i] == 43)
After replying you,i’ve also used ascii number..as (reply[i] == 33) for !.but it’s not working
Hi,
Thanks for your example.
It runs ok for the setup() part for me. But I can’t connect to it. I write 192.168.1.32:80 on my browser on a machine connected to the same network and… nothing happens.
Nothing on my browser (tested with chrome and firefox) and nothing on the serial…
Do you have any clue to help me ?
Have a nice day !
Maxime.
Does the ESP8266 connect to the local network OK? Check that the ESP8266 is visible. Use a network scanning tool to scan for wifi devices.
Tom,
what are you actually wanting to do? Character 33 is the exclamation mark. This would only be there if it is part of the name. Going back to the original example. The space is replaced with the plus sign so “Bessy Smith” becomes “Bessy+Smith”. A simple way to change it back is
if ( !finishedCopying )
{
if (reply[i] == 43) { reply[i] = 32; }
name[tempPos] = reply[i]; tempPos++;
}
I am wanting to show special characters..like:!,@#$% etc;
your last suggestion was working for space..but what for others..?
ok, I understand know.
Special characters are encoded as hexadecimal ascii values of the character. ! becomes %21, @ becomes %22, # becomes %23. etc
You need to check for the % character and when you get one you know the next 2 characters are the hexadecimal value of the special character.
really great!! thanks a lot :)
Hi,
Great job, it work on my arduino uno. This is the most detailed tuto i found on the web.
I have a question, I want to send a voice file to web server. Do you know how to build a code for this?
Best regards
Hunny
This is beyond the scope of the above guide. If you have not already, join the Arduino forum and ask there. You should get the help you need.
http://forum.arduino.cc/index.php
hi can said me please where i can download libarys? i cant found on anyplace
im looking for esp8266WebServer.h esp8266WiFi.h esp8266mDNS.h
thanks a lot
I have added links at the top of the post.
Thanks
Hallo,
I would like to know if there are new libraries of arduino for ESP8266 and how to find them, i saw your links but i would like to find them just like you did.
Thanks in advanced.
Google: Arduino + Esp8266 + library.
tienes algun ejemplo de lectura analogica con arduino plugin? excelente aporte
Amazing and very informative stuff. Really very helpful for my arduino project. Thanks for sharing a great post with us.
Many thanks for this example but it takes a very long time to load the page. Why the long timeouts on every getReply and would it hurt to reduce them to the 200ms range?
You can change the wait time by changing the value in getReply(). A better method would be to wait for the reply and use the timer as a time out.
Be aware that this is a very old example that I wrote shortly after the ESP8266 modules were available and there are better examples available. Google for arduino + esp8266 server.
Thank you so much.It really helpful me.
I really need your help. Please answer me here or lexuanbac291193@gmail.com
when we set esp8266 01 as a access point we have a ip address.
And when we set esp8266 01 as a station(client) we have another ip address.
In this case( your code) where ip address we have to go to control ?( I mean the ip address you use to control). Thanks
In the above example the ESP8266 is used in station mode. This means it acts like any other wifi enabled device and is allocated an ip address from the router.
When used as an access point (AP) you can think of the ESP8266 as a router that other devices can connect to directly. In this mode the ESP8266 allocates ip addresses.
why the webpage can not display ,thi is my serial print
Start
reset the module
AT+RST
OK
—–
version
Ltd.
ready
AT+GMR
AT version:0.21.0.0
SDK version:0.9.5
OK
—–
Change to station mode
AT+CWMODE=2
OK
—–
Connect to a network
Get the ip address assigned ny the router
AT+CIFSR
+CIFSR:APIP,”192.168.4.1″
+CIFSR:APMAC,”1a:fe:34:0c:e6:a7″
OK
—–
Set for multiple connections
AT+CIPMUX=1
OK
—–
Start the server
AT+CIPSERVER=1,80
OK
—–
Waiting for page request
Connect to +CIFSR:APIP,”192.168.4.1″
0,CONNECT
+IPD,0,353:GET /?name=0 HTTP/1.1
Host: 192.168.4.1
Connection: k
—–
name = 0
AT+CIPSEND=0,20
OK
>
—–
—–
AT+CIPSEND=0,26
busy s…
SEND OK
—–
ESP8266 Webserver
—–
AT+CIPSEND=0,14
OK
>
—–
SEND OK
—–
can i change arduino with teensy in the same code
I doubt it but I have actually tried. Give it a go an see what happens.
is it possible to assign ip address for the esp?
In the above example the IP address is assigned by the router.
If you mean you want a static IP address, one that you specify in the code than have a look at https://github.com/esp8266/Arduino/issues/1959 or google esp8266 static IP address. There are lots of guides online.