Introduction: Easy ESP8266 (Arduino Core) Web Controls With EmbAJAX

If you came here, you have probably started playing with an ESP8266 as a web server, before. But if you have not: It's incredibly easy to implement a webserver on an ESP8266, and you should try this, today! (The hardest part is getting familiar with how to connect and program your ESP8266 - I will give you some links on this in Step 1).

However, once that is accomplished, you don't want to simply serve static content, you want to display changing information such as temperatures or other sensor readings, and you want to add controls to allow turning on and off lights, etc. The general approach to doing so is using a family of techniques known as "AJAX" or Asynchronous Javascript and XML (where XML is typically replaced with JSON in contemporary applications). That is a relatively straight-forward technique to manage data exchange between a web server (your ESP8266), and a web client (browser on your smartphone or PC). You will not have trouble finding basic examples of controlling a single switch from a single client, for instance. However, once you need to pass information both ways (client to server and back), once you deal with more than one client, once you start worrying about lost network connections, etc. you will start to realize that all of this is more cumbersome than you thought at first.

One popular way out of this mess is Blynk. However, maybe - like me - you are a stubborn old-school fool who fails to see why you would need to sign up to a service, and download an app, when you already have an embedded webserver up and running, and a choice of web browsers on any device.

Fear not! Rolling your own AJAX - all registration free, and based on public standards - has just become easy. I'm going to give you a brief introduction to EmbAJAX, and then you can finally start worrying about what you are going to implement in your IoT project, instead of how.

Step 1: Preliminaries: Setting Up You ESP8266 for Arduino

There are many ways to use an ESP8266, including using it as a simple WiFi modem, connected to an Arduino, or running a scripting language ("Lua") on it. In this instructable we will use an ESP8266 flashed with an Arduino core, instead. This means, in essence, that once set up, you can program your ESP8266 from the regular Arduino IDE. This has a lot of advantages: It offers very good performance, there is a huge community of users, you will find tons of code examples, and libraries for various hardware... But, admittedly, it may be a tad bit complicated to set up for the first time.

Fortunately, others have already written excellent instructions on how to do just that. E.g. this instructable, or this one (using a different technique for programming). If all of this looks a bit scary, you can make your entry into the ESP8266 world a whole lot easier (but marginally more costly) by using a board with a USB connector, such as the Wemos D1. Very thorough instructions for that (also applicable for many similar boards) are given here, for example.

Step 2: Preliminaries 2: Set Up a Webserver on Your ESP8266

Now that your ESP8266 is set up for use with the Arduino environment, we can start programming. Just to make sure we're on the same page of the textbook, we'll start by setting up a simple web server to greet us with a static message. Here's all the code you need for that:

#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>

// create a web server on port 80 (HTTP)
ESP8266WebServer server(80);

// this function is called for each HTTP request
void handlePage() {
  server.send(200, "text/plain", "Hello world!");
}

void setup() {
  // Example WIFI setup as an access point. Change this to whatever suits you, best.
  WiFi.mode(WIFI_AP);
  WiFi.softAPConfig (IPAddress (192,168,4,1), IPAddress (0,0,0,0), IPAddress (255,255,255,0));
  WiFi.softAP("EmbAJAXTest", "12345678");

  // register the page handler and start the server
  server.on("/", handlePage);
  server.begin();
}

void loop() {
  // inside loop(), add this line to check for and handle incoming connections
  server.handleClient();
}

The sketch is so simple it hardly needs explaining beyond the in-line comments. One thing I'd like to point out is that in this example (and the following ones), we set up the ESP8266 as a wireless access point. This provides a very simple but effective security mechanism: Only clients that are in range, and know the session password can connect.

Ok, so upload the sketch to your ESP8266. Next, on your PC, start up your WiFi connection manager, scan for a network called "EmbAJAXTest", and connect (password is "12345678", as configured in the sketch). Now fire up a web browser, and enter "http://192.168.4.1" in the location bar. You should be greeted with the message "Hello world!".

Step 3: Installing EmbAJAX

Did everything work, so far? Great! The next steps will be easy. First we have to install the EmbAJAX library. As usual, there are many ways to accomplish this, but here's one:

  1. Download a ZIP of the library.
  2. In your Arduino IDE, select "Sketch->Include Library->Add .ZIP Library", and select the ZIP you downloaded.
  3. For good measure, restart Arduino (probably not needed, though)

To verify that EmbAJAX is installed, properly, check whether anything is listed below "File->Examples->EmbAJAX".

Step 4: Blink Your LED - Web Controlled

Well, I promised you can do more than just blink an LED with EmbAJAX, but it's still a useful example to get started with. We'll extend the example from Step 3 a bit. (The following listing is taken directly from the "Blink" example that ships with the EmbAJAX library: "File->Examples->EmbAJAX->Blink").

#include <ESP8266WiFi.h><br>#include <ESP8266WebServer.h>
#include <EmbAJAX.h>

#define LEDPIN LED_BUILTIN

// Set up web server, and register it with EmbAJAX
ESP8266WebServer server(80);
EmbAJAXOutputDriverESP8266 driver(&server);

// Define the main elements of interest as variables, so we can access to them later in our sketch.
const char* modes[] = {"On", "Blink", "Off"};
EmbAJAXRadioGroup<3> mode("mode", modes);
EmbAJAXSlider blinkfreq("blfreq", 0, 1000, 100);   // slider, from 0 to 500, initial value 400

// Define a page (named "page") with our elements of interest, above, interspersed by some uninteresting
// static HTML. Note: MAKE_EmbAJAXPage is just a convenience macro around the EmbAJAXPage###>-class.
MAKE_EmbAJAXPage(page, "EmbAJAX example - Blink", "",
  new EmbAJAXStatic("<h1>Control the builtin LED</h1><p>Set the LED to: "),
  &mode,
  new EmbAJAXStatic("</p><p>Blink frequency: <i>SLOW</i>"),
  &blinkfreq,
  new EmbAJAXStatic("<i>FAST</i></p>")
)

void handlePage() {
  if(server.method() == HTTP_POST) { // AJAX request
    page.handleRequest(updateUI);
  } else {  // Page load
    page.print();
  }
}

void setup() {
  // Example WIFI setup as an access point. Change this to whatever suits you, best.
  WiFi.mode(WIFI_AP);
  WiFi.softAPConfig (IPAddress (192,168,4,1), IPAddress (0,0,0,0), IPAddress (255,255,255,0));
  WiFi.softAP("EmbAJAXTest", "12345678");
  // Tell the server to serve our EmbAJAX test page on root
  server.on("/", handlePage);
  server.begin();
  pinMode(LEDPIN, OUTPUT);
}

void updateUI() {
  // Enabled / disable the slider. Note that you could simply do this inside the loop. However,
  // placing it here makes the client UI more responsive (try it).
  blinkfreq.setEnabled(mode.selectedOption() == 1);
}

void loop() {
  // handle network
  server.handleClient();
  // And these lines are all you have to write for the logic: Access the elements as if they were plain
  // local controls
  if (mode.selectedOption() == 1) { // blink
      digitalWrite(LEDPIN, (millis() / (1100 - blinkfreq.intValue())) % 2);
  } else {  // on or off
      digitalWrite(LEDPIN, mode.selectedOption() != 0);
  }
}

Ok, this listing is a bit longer, but you will find it's mostly harmless. To start from the top, we now added the EmbAJAX libraray to the sketch (obviously). Next we define the pin to blink an LED on. Surprisingly, this is one of the more complex points, as ESP boards differ wildly on where their on-board LEDs are connected. If all else fails, you may have to adjust this define to connect an external LED (with resistor!) to one of the GPIO pins.

Next, we define an "output driver" in addition to the web server instance. Don't worry about this line, essentially you're just telling the EmbAJAX library where to send and receive data.

The following lines are more interesting: We define some EmbAJAX elements, importantly a group of radio buttons, and a slider. These are then added to a web page (MAKE_EmbAJAXPage). In addition to the radio and the slider, this contains a few static elements. Try adding your own. It may look complex at first, but it's actually very straight-forward.

The handlePage()-function is now very slightly more complex: It now differentiates between "GET"-requests (normal page loads), and "POST"-requests (which are used to transfer the AJAX data). Fortunately, we don't have to fill in anything complex, here. The one bit you need to worry about is providing the name of a function to call whenever a change has been signalled by the client (updateUI(), detailed below).

Compared to our static web server example, setup() is virtually unchanged. The only addition is that we set the output mode of the LED pin.

updateUI() is called whenever one of the controls is changed in the web client. What we do in this function is to set the slider element enabled, if and only if the "blink" option has been selected in the radio group. And this is actually the first point where I hope you will think "that's neat": Note that you deal with the controls as if they were plain local objects. You do not have to worry about sending or receiving any data. All of that is handled by the library.

Similarly inside loop, the controls appear just like local objects. You query their current state and act upon that (note that these operations are very fast; they do not involve network requests for each call, as they are in fact asynchronous).

Enough of the theory! Upload the sketch, and reload "http://192.168.4.1" in your browser. (You may or may not have to re-connect to the "EmbAJAXTest" WiFi network after your ESP8266 has rebooted; that will depend on your system and settings.) You should see a radio group and a slider. Start playing!

Step 5: Where to Go From Here

A radio button and and a slider are not much, but of course EmbAJAX has more elements than just that. Above is a screenshot of browsing the "Inputs"-example ("File->Examples->EmbAJAX->Inputs"). This shows the controls that are currently available in EmbAJAX. You know what to use these for in your project, so I'm not going to provide any further examples, but simply point you to the EmbAJAX API documentation. Note that you can also add custom CSS for styling.

As only one more thing about the inputs example, I will point out that the values shown on the right hand side are set from the server. The point is to demonstrate a full circle from

  • control changed in the client
  • change propagated to and handled in the server
  • updated state sent back to the client

In case you do not find that terribly exciting - well, I will forgive your lack of enthusiasm. That's exactly what the EmbAJAX library is all about: It relieves you of all the boring behind the scenes work, and you are finally free to worry about what controls and displays you want to show in your project, rather than how. So - happy developing!