Arduino IDE for ESP8266
The Arduino IDE version 1.6.1 with ESP8266 support worked well as a webserver using the WiFiWebServer example sketch as a starting point. This basic example supports on/off control of an LED from a web browser. The example demonstrates how to interpret and respond to requests. It can easily be expanded to support responses any request strings added to the domain:port URL used to access the device. The example, which simply controls an LED, uses domain:port/gpio/0 to turn the LED off and domain:port/gpio/1 to turn it on.
Building my sketch on the back of this example, I soon uncovered issues which had to be addressed in order for my IoT sensor reads to function as required. This included:
1. WiFi Connection
The connection can and sometimes does get dropped. It is important to have a check in the sketch loop() function to reconnect if it is disconnected.
if (WiFi.status() != WL_CONNECTED) {
delay(1);
WiFi.config(ipadd, ipgat, ipsub);
WiFi.begin(ssid, password);
//Wait here until connected, up to a timeout period
while (WiFi.status() != WL_CONNECTED) {
Serial.print(“.”);
delay(500);
}
return;
}
2. Ticker
Ticker is supposed to provide the capability to perform periodic tasks. This must be using the SDK timer/callback API. While it worked flawlessly for me with the SDK, it did not work well with the Arduino loop(). I was trying to separate the sensor reads from the server handler, using the timer for sensor reads. Erratic resets occurred. From my experience, Ticker is not usable at this time. With the current Arduino IDE, it is necessary to handle all code single threaded within the sequence of the loop() function.
3. Watchdog Timer Resets
Disable the watchdog timer and the MPU will halt on the first timeout. It must remain enabled during normal code execution. But I have observed many resets when trying to read attached sensors while also supporting the web server. These resets can be reduced or eliminated by structuring the loop() function with returns after every time consuming task, like reading a sensor. The resets are also reduced by using yield(), delay() and ESP.wdtFeed() statements after time consuming tasks.
4. Math Functions
Using the BMP085 to read Barometric Pressure require use of the pow function. This math function is not supported with the core library and attempts to link the math.h library blows the memory, resulting in a build error. Since the pow function is only used for the calculation of altitude values, the BMP085 will work with the Arduino IDE if you comment out the pow functions in the library and only read the pressure and temperature values from the device driver.
5. JSON Encoding
The JSON library included with the SDK is not available with the Arduino IDE. And linking a JSON library will blow the memory. Since it is advantageous to return a JSON string with sensor values in response to “http GET” requests, this becomes a significant shortcoming. But a simple JSON encoding function used to build the return string is all that is needed to overcome this. This works with minimal code:
void jsonAdd(String *s, String key,String val) {
*s += ‘”‘ + key + ‘”‘ + “:” + ‘”‘ + val + ‘”‘;
}
void jsonEncode(int pos, String * s, String key, String val) {
switch (pos) {
case ONEJSON:
case FIRSTJSON:
*s += “{\r\n”;
jsonAdd(s,key,val);
*s+= (pos==ONEJSON) ? “\r\n}” : “,\r\n”;
break;
case NEXTJSON:
jsonAdd(s,key,val);
*s+= “,\r\n”;
break;
case LASTJSON:
jsonAdd(s,key,val);
*s+= “\r\n}”;
break;
}
}
6. Watchdog Timer Functionality
A richer API to the watchdog timer is needed. This may just be a wish list, but it would be very helpful if the timeout period could be set and a user defined callback function could be registered for timeouts. This would go a long way in resolving the device resets experienced by many ESP8266 users.
In summary
The Arduino IDE is a very well-known and supported platform. These shortcomings will probably be overcome with updates in the future. Despite the limited flexibility and functionality of the Arduino IDE, it will likely be the platform of choice for many ESP8266 application developers.
Hi!
Thank you for your comments. I have an issue with my ESP8266 01….I have made a sketch using the example mentioned in your message. It works well, but after one ore two days, no way to connect to the ESP. I need to turn off/on the power and it works again immediately. Two days later, same issue….I have included in the void loop() your code (1.WIFI Connection paragraph) to have a check to reconnect it….No difference !! Always the same problem….
May be I am doing something wrong, but I cannot find what, I am not an expert…..
Could you help me to solve this issue?
Many thanks !
Philippe
Below is the sketch I have loaded on my ESP:
#include
int ledPin = 2; // GPIO2
const char* ssid = “XXXXXX”; //your wifi ssid
const char* password = “YYYYYYYY”; //your wifi password
const uint8_t ipadd[4] = {192,168,1,181}; //static ip assigned to ESP8266
const uint8_t ipgat[4] = {192,168,1,1}; //local router gateway ip
const uint8_t ipsub[4] = {255,255,255,0};
WiFiServer server(80);
//——————————————-
//———————————————————
void setup() {
Serial.begin(115200);
delay(10);
pinMode(ledPin, OUTPUT);
digitalWrite(ledPin, LOW);
// Connect to WiFi network
Serial.println();
Serial.println();
Serial.print(“Connecting to “);
Serial.println(ssid);
WiFi.config(ipadd,ipgat,ipsub);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(“.”);
}
Serial.println(“”);
Serial.println(“WiFi connected”);
// Start the server
server.begin();
Serial.println(“Server started”);
// Print the IP address
Serial.print(“Use this URL to connect: “);
Serial.print(“http://”);
Serial.print(WiFi.localIP());
Serial.println(“/”);
}
void loop() {
//connect wifi if not connected
if (WiFi.status() != WL_CONNECTED) {
delay(1);
WiFi.config(ipadd,ipgat,ipsub);
WiFi.begin(ssid, password);
//wait until connected, up to a timeout period
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(“.”);
}
return;
}
// Check if a client has connected
WiFiClient client = server.available();
if (!client) {
return;
}
// Wait until the client sends some data
Serial.println(“new client”);
while(!client.available()){
delay(1);
}
// Read the first line of the request
String request = client.readStringUntil(‘\r’);
Serial.println(request);
client.flush();
// Match the request
int value = LOW;
if (request.indexOf(“/LED=ON”) != -1) {
digitalWrite(ledPin, HIGH);
value = HIGH;
}
if (request.indexOf(“/LED=OFF”) != -1) {
digitalWrite(ledPin, LOW);
value = LOW;
}
// Set ledPin according to the request
//digitalWrite(ledPin, value);
// Return the response
client.println(“HTTP/1.1 200 OK”);
client.println(“Content-Type: text/html”);
client.println(“”); // do not forget this one
client.println(“”);
client.println(“”);
client.print(“Led pin is now: “);
if(value == HIGH) {
client.print(“On”);
} else {
client.print(“Off”);
}
client.println(“”);
client.println(“Click here turn the LED on pin 2 ON”);
client.println(“Click here turn the LED on pin 2 OFF”);
client.println(“”);
delay(1);
Serial.println(“Client disonnected”);
Serial.println(“”);
}
Hi Philippe,
Thanks for your comment. I noticed you are referring to a post I wrote 4/24/15 discussing issues with the Arduino IDE. Since that time, I have had considerable experience with the ESP using the Arduino IDE and found that the EspressIf SDK model for a Web Server is far superior to the polling for messages as described in the 4/24/15 post. I highly recommend that you consider the approach used here http://wp.me/p5NRQ8-jc for your ESP Web Server projects.
From what you have described, it would seem that something goes wrong in the loop() after a day or two of continual operation. From my experience, a slow memory leak would be suspect, reducing the heap until the ESP crashes without a means to recover without a power reset. The best way to determine what is happening when you can no longer connect to the ESP is to use the serial output as a data recorder. Pop out messages periodically that will give you a clue as to what is going wrong. Using a terminal program such Tera Term, you can record all output sent to the serial port. At the time that the ESP no longer responds, you will probably even observe the reset event in the output.
The first part of the loop already outputs something every time the WIFI is dropped and a reconnect is attempted. And you also get a serial output anytime a web connection is made.
Here is what I would suggest adding:
1. A time tag printed each time a WIFI reconnect is needed:
unsigned long time;
time = millis();
Serial.print(“Current ESP time(ms): “);
Serial.println(time); //prints time since program started
2. I would also add an output of the free heap periodically (once every 5 seconds or so, but not every loop):
Serial.print(system_get_free_heap_size()); //You could also time-tag these free heap snapshots
You will need one of the headers from the SDK to get the heap. I am not sure which one it is but I do know it is in this list. There is no harm in including all of these at the top of your script:
// Include API-Headers
extern “C” { //SDK functions for Arduino IDE access
#include “ets_sys.h”
#include “os_type.h”
#include “osapi.h”
#include “user_interface.h”
#include “cont.h”
#include “espconn.h”
#include “eagle_soc.h”
}
But honestly, here is my best recommendation again:
I highly recommend that you consider the approach used here http://wp.me/p5NRQ8-jc for your ESP Web Server projects.
Good luck with your projects.
Hello!
First of all, I would like to thank you for your so quick answer! It is really appreciate!
Indeed, you have work a lot on the ESP…! Even if I am not an expert, I understand that your approach by using a callback is better.
I will try to use your sketch find on Github and follow the setup procedure after downloading the zip file. I need also to copy the tree folders in Arduino IDE. Hope it will be easy to do that (never done it before…).
Could I use my ESP8266-01 (normally yes regarding your comments: code will work with any ESP circuit….)? However, there is only two GPIO pin, 0 and 2…So, for the LED connection, do I need also to change :
#define LED_IND 16 to #define LED_IND 2 (to use GPIO 2)?
Thanks for your help!
Kind regards,
Philippe
hi
how can i store the the status of each switch so i can when button is pressed the LED will ON if again pressed the LED will off?please suggest me.Thanks in advance
Suggested Solution: In your callback routine when a button is pressed, I would first read the state of the switch. Then change it to the opposite state:
state = digitalRead(PIN_NO);
digitalWrite(PIN_NO, !state );
Hello
I tried to create ticker for reading BMP180 sensor values. When reading that sensor in ticker values are too small. But with only loop reading values are ok. So there is something strange with tickers instead of sensor library. Then I realized that I cannot even use tickers and loop at the same time.
I thought that it was good idea to use four tickers for reading different sensor, blinking led and sending data to IoT cloud. For me it is not big deal to change code to use some Arduino timer library which handles everything in loop.
With the Arduino IDE, I use a function named “ReadSensors(ms)” in my loop. A single parameter is passed to tell the function how often to read the sensor, in milli-seconds. I have used sensors such as your BMP180 as well as multiple 1-wire DS18B20 sensors with a single ESP and found that slow moving sensors do not require a fast refresh rate. In order to make sure the everything (sensor reads, cloud updates, web server) runs smoothly, I have limited sensor readings to one sensor every 2.5 seconds. Here is the ReadSensor() function logic:
This gets called once every loop():
void ReadSensors(int interval) {
yield();
long now = millis();
if (now - lastMsg > interval) { // Read 1 sensor every "interval" milliseconds or longer
lastMsg = now;
}
else {
return; // less than "interval" since last sensor read
}
readSensorIsr();
}
Reading sensors (1 read/function call)
void readSensorIsr() {
yield();
switch(state++) {
case 0:
getTempDs18b20(1, tin);
break;
case 1:
getTempDs18b20(2, tout);
break;
case 2:
getTempDs18b20(3, tatt);
break;
case 3: //Read Baro Temperature
if(bmp085_present) {
bt = (bmp.readTemperature() * 9/5) + 32;
ftoa(bt,btmp, 1);
}
else {
strcpy(btmp,tin);
}
break;
case 4: //Read Baro Pressure
if(bmp085_present) {
bp = bmp.readPressure() / 3386;
ftoa(bp,bprs, 1);
}
else {
strcpy(btmp,"29.5");
}
break;
case 5: //Calc Baro Altitude (does not work-pow from math.h library not linked properly)
//ba = bmp.readAltitude(bmp.readSealevelPressure(555/3.28)) * 3.28;
ba = 550.0;
ftoa(ba,balt, 1);
break;
case 6:
dhth = dht.readHumidity();
ftoa(dhth,dhhumi, 1);
break;
case 7:
dhtt = dht.readTemperature(true);
ftoa(dhtt,dhtemp, 1);
state=0;
break;
default:
break;
}
ESP.wdtFeed();
yield();
}
are you doing any blocking calls (like serial,wifi) using ticker ?. i as using ticker i faced resets it seems to be stopped after removing the blocking calls . i just want to see the code which causes random resets
It has been a long time since I have experienced reset issues. Blocking calls will definitely cause resets.
You also need to be careful with sensor readings that could exceed the WDT timeout. I have found it a good practice to reset the WDT when performing lengthy tasks, adding:
ESP.wdtFeed();
yield();
as appropriate.
It is also a good practice to limit the tasks performed each loop(), using a state machine to cycle through your task list, running only a limited operation each iteration.
And since most applications involve a web server, requests should be handled with callbacks instead of polling in the loop(). That is another blocking source.