The objective of this ESP8266 Arduino tutorial is to get familiar with embedded programming with Arduino on a chip that’s become super popular among the maker community (and developers in general) for its accessibility and ease of use in the IoT space. The tutorial also gets our hands dirty with Alexa using an unofficial “hack” to get Alexa to do our bidding in the home (this technique is not meant for use in production, only for at-home demonstration). Try this at home, but not at work.

Abstract graphic representation of ESP8266 Arduino tutorial

The beauty of this technique is that we can use it in our own homes to make Alexa automate almost literally anything that runs on electricity. As an added bonus, we get an insight into embedded programming with Arduino, a skill that’s maybe not so common among mainstream programmers these days. Finally, we get to work with the popular ESP8266 chip, a favorite among do-it-yourselfers; it’s an amazing little chip with ability to run all sorts of things, with a built-in Wifi chip that we will need for this project. It’s what will enable the Alexa device and the chip to communicate with one another directly.

Just some background on Alexa programming: The Alexa “skills” programming model works like this:

Abstract graphic representation of Alexa

  • You speak to your Alexa.
  • Alexa routes your speech all the way back to Amazon’s cloud.
  • The speech command is routed to an Alexa “skill” (a program that runs in Amazon’s cloud).

The Alexa “skill” takes over handling of the command; normally it results in a response being sent back to the Alexa device, causing it to say something to the user in response. In the case of Alexa IoT, the command gets routed to a “device shadow” on Amazon’s cloud, which in the end results in a response being sent to some other device in your home. We are bypassing all that with our hack. We want to make the Alexa device talk directly to our ESP8266 chip, inside of our home, without sending anything out to the cloud and back. We want the Alexa to directly send a request to our ESP8266, over and inside of our home wifi network only.

Our hack is not really a secret. We are going to make our ESP8266 “emulate” a Wemo Belkin, a device that has a special license with Amazon allowing it to communicate directly with the Alexa device, bypassing all of that Amazon cloud communication described above.

Pretending to be a Wemo, our ESP8266 enjoys the privilege of being able to receive commands directly from the Alexa.

Basic Plan for our ESP8266 Arduino Tutorial

  • Listen on the ESP8266 for the Alexa device sending out probes on the local wifi network for compatible devices, and respond to these probes by saying “I’m a Wemo.”
  • Once trusted by the Alexa device, listen for further commands from said device. Handle them by sending IR codes through the IR transmitter, turning our TV on/off.

Hardware Requirements

Abstract graphic representation of pieces of hardware, including an Alexa tower and an Arduino board

To complete this tutorial, you’re going to need to obtain some items on your own, all of which are easy to obtain.

  • Any Alexa device. I’ve developed this tutorial with an Alexa Dot. Will the tutorial work with an Echo simulator? It might! (But I haven’t tested it). Give it a try if you’re feeling adventurous (or frugal). The Alexa device costs pocket money, but use of the Echosim is free.
  • An ESP8266 chip. They cost about just a few USD at the time of this writing. You can get them on Ebay, or just about any well-stocked hardware shop online.
  • An IR (infrared) diode. You’ll need to wire this to your ESP8266 chip, and this you’ll have to do yourself. For this project, we only need the sending capabilities; we don’t care about IR receiving. Be sure to wire the diode to GND and output 0 for this tutorial to work. (If you do it in any other way, that’s fine, but you’ll have to also be responsible for modifying the tutorial code accordingly. This link may help you. Be cognizant that due to the numbering scheme used on the ESP8266, pin 0 may be labeled as “D3.”
  • A serial adapter which on one side is USB (to plug into your dev computer), and the other side fits into the ESP8266 chip.
  • A local wifi network to which you know the username and password.
Photograph of ESP8266 attached to adapter, next to Echo Dot
ESP8266 attached to adapter, next to Echo Dot
Photograph of ESP8266 with IR diode attached
ESP8266 with IR diode attached

Arduino Software Tools

  • Arduino IDE. There are versions for all major OSes, including Windows. This tutorial was developed on the Ubuntu version, but I’ve installed and used Arduino on Windows as well, no problems.
  • The ESP8266 development library for Arduino.
  • Drivers. Luckily, drivers for your adapter should most likely be plug & play, so no additional drivers are required.

Setting Everything Up

To install ESP8266 library using Boards Manager:

ESP8266 Arduino tutorial screenshot highlighting the Boards Manager URLs field

  • Go to Boards Manager (Tools -> Board: [current board] -> Boards Manager). Screenshot highlighting the Boards Manager menu item

  • In the “filter” text box, type “ESP8266.”
  • You should get an entry for “esp8266” now that you have the additional boards manager added. Choose it, and click “install.”

ESP8266 Arduino tutorial screenshot of the Boards Manager highlighting the installation process

  • Wait a while—it takes some time to download everything.
  • Restart your Arduino IDE.
  • Open Tools -> Board: and, this time, scroll down to “Generic ESP8266 Module” and select it.

ESP8266 Arduino tutorial screenshot highlighting the menu option for Generic ESP8266 Module

Adding Third-party Libraries

Arduino offers many different ways to add external libraries to your project, or “Sketch,” as they call it. To keep things as simple as possible, for this tutorial, we will just take the quickest to explain, which is to simply copy folders. We will need to add exactly two external libraries for the tutorial to work: IRemoteESP8266 and https://github.com/me-no-dev/ESPAsyncTCP.

  • In the tutorial code in GitHub, find the “libraries” directory.
  • In the root installation directory for Arduino (e.g., C:\Program Files\Arduino), find the “libraries” subdirectory.
  • Copy the IRemoteESP8266 directory from the tutorial’s “libraries” directory into Arduino’s “libraries” directory.
  • Copy the ESPAsyncTCP directory from the tutorial’s “libraries” directory into Arduino’s “libraries” directory.
  • Restart the Arduino IDE.

Now the libraries for IR transmitting and async TCP are included in the project.

Settings

The image below shows typical settings, which work for me and my hardware but may vary for each user. You can try the settings below, but there’s a chance that you may have to adjust them based on your particular chip and adapter. Mine is nodemcu, for example, so I had to change reset method from “ck” (the default) to “nodemcu.” Also, set “debug port” to “serial” so that you can use the serial debugger. Mine is a very typical setup, so you can use my settings as a base; I’m just saying don’t be surprised if you have to mess with them to get the compile and flash process to work.

Screenshot of the Serial debug port menu option

Prove Your Setup with an ESP8266 Hello World

Arduino projects start with an .ino file. The .ino file defines two points of entry: setup and loop. For our “hello world”, we’re going to turn a little light on, on the ESP8266, just to verify that our code works.

//SET TO MATCH YOUR HARDWARE 
#define SERIAL_BAUD_RATE    9600
#define LED_PIN 2

/*---------------------------------------*/
//Runs once, when device is powered on or code has just been flashed 
void setup()
{
    //if set wrong, your serial debugger will not be readable 
    Serial.begin(SERIAL_BAUD_RATE);
    pinMode(LED_PIN, OUTPUT);
}


/*---------------------------------------*/
//Runs constantly 
void loop()
{
	digitalWrite(LED_PIN, LOW); 
	delay(1000); 
	digitalWrite(LED_PIN, HIGH);
	delay(1000); 
}

Compile and Flash the Code

To compile and flash are easy steps, if your setup so far is correct. To compile without flashing, just go to Sketch -> Verify/Compile from the Arduino menu.

Screenshot of the Upload menu option in the Sketch menu

To flash the code to the chip as well as compile, select Sketch -> Upload from the Arduino menu.

Screenshot of the upload in progress

If the flash is successful, you will see a progress display go from 0% to 100%, during which time the LED on your chip will most likely actually blink or flash.

To test that serial debugging is working:

  • First make sure that debug port is set to Serial (Tools -> Debug port).
  • After your code has finished flashing to the chip, select Tools -> Serial Monitor.

Screenshot of the Serial debug port menu option

Output of serial debugger after a successful start:

Screenshot of the output of a serial debugger after a successful start

Great, so that works; next, we want to verify our IR output. Let’s send a signal through our IR transmitter and verify that the signal’s coming through.

We’re going to make use of an existing Arduino IR library to help us. One of the great things about Arduino is how easy it is to snap libraries and modules in and out. Very refreshing for a C++ framework!

Just follow the instructions in that Git repo’s README file to install in Arduino.

This code just flashes the IR transmitter repeatedly. IR is invisible to the human eye, but there’s a pro-tip for testing it; run this code, verify (via the debugger) that it’s running on your chip, then open your mobile device’s camera. Look directly at the IR diode bulb through your camera. If it’s working, you should see the bulb visibly turning on and off. You can try this with any working remote control as well (e.g., a standard TV remote). The following code should cause the IR bulb to start flashing every 0.5 second. Actually it sends the LG on/off command, so it may actually turn your LG TV off and on if it’s nearby.

#include <IRremoteESP8266.h>    // IR Library


IRsend* irSend;                 // infrared sender

//SET TO MATCH YOUR HARDWARE 
#define SERIAL_BAUD_RATE    9600

//PIN 0 is D3 ON THE CHIP 
#define IR_PIN              0 

/*---------------------------------------*/
//Runs once, when device is powered on or code has just been flashed 
void setup()
{
    //if set wrong, your serial debugger will not be readable 
    Serial.begin(SERIAL_BAUD_RATE);

    //initialize the IR 
    irSend = new IRsend(IR_PIN, true);
    irSend->begin();
}

/*---------------------------------------*/
//Runs constantly 
void loop()
{
    irSend->sendNEC(0x20DF10EF, 32, 3);
    delay(1000);
}

Begin the ESP8266 Tutorial

If everything has worked so far, I think we can be satisfied that our basic equipment and setup are working, and we’re ready to begin the meat of the tutorial.

Connect to Wifi

First, we’re going to need to connect to the local wifi. The code below will attempt to connect to the Wifi, and reports success on connection (through the serial debugger). In the code sample, don’t forget to replace myWifiSsid’s value with the username of your wifi network, and replace myWifiPassword’s value with the correct password.

#include "debug.h"              // Serial debugger printing
#include "WifiConnection.h"     // Wifi connection // this file is part of my tutorial code
#include <IRremoteESP8266.h>    // IR library 


WifiConnection* wifi;           // wifi connection
IRsend* irSend;                 // infrared sender


//SET YOUR WIFI CREDS 
const char* myWifiSsid = "***";
const char* myWifiPassword = "*******";

//SET TO MATCH YOUR HARDWARE 
#define SERIAL_BAUD_RATE    9600

//PIN 0 is D3 ON THE CHIP 
#define IR_PIN              0



/*---------------------------------------*/
//Runs once, when device is powered on or code has just been flashed 
void setup()
{
    //if set wrong, your serial debugger will not be readable 
    Serial.begin(SERIAL_BAUD_RATE);

    //initialize wifi connection 
    wifi = new WifiConnection(myWifiSsid, myWifiPassword);
    wifi->begin();

    //connect to wifi 
    if (wifi->connect())
    {
        debugPrint("Wifi Connected");
    }
}


/*---------------------------------------*/
//Runs constantly 
void loop()
{
}

Run the Wemo Server

Connected? Good. Now we’re getting to the meat of the project: the Wemo server.

My own Wemo Emulator is included in the source files for this tutorial. Now, you can search Google and find a simpler Wemo emulator. You can find one that’s written using less code, and which is easy to understand. By all means, feel free to examine, experiment, write your own, etc. That’s all part of making this tutorial your own.

The reasoning behind mine is that it uses ESPAsyncTCP. Why is this good? Well, there are only so many servers (or devices) you can run on the ESP8266 using this method before it starts becoming unreliable, in the sense that the Alexa will start missing devices (not finding them), commands will get dropped, and performance becomes slow. I find that this number is maximized by use of the ESPAsyncTCP library.

Without it, I’ve found unreliability to creep in at around 10-12 devices; with it, I find that number ups to around 16. In case you’d like to expand this tutorial and explore the limits of what the chip can do, I’d recommend using my version. If you want to see a simpler version just for your own understanding, feel free to search “wemo emulator Arduino” on Google; you should find a host of examples.

Now, we have to install the ESPAsyncTCP library. Install it just as we did the IR library; go to the Git page and follow the instructions.

This library’s included in my esp8266 arduino example code as well. Here’s just the code to open the wifi connection, listen for the Alexa discovery request, and handle it by returning an “I am Wemo” response.

#include "debug.h"              // Serial debugger printing
#include "WifiConnection.h"     // Wifi connection 
#include "Wemulator.h"          // Our Wemo emulator 
#include <IRremoteESP8266.h>    // IR library 


WifiConnection* wifi;           // wifi connection
Wemulator* wemulator;           // wemo emulator
IRsend* irSend;                 // infrared sender


//SET YOUR WIFI CREDS 
const char* myWifiSsid = "***";
const char* myWifiPassword = "*******";

//SET TO MATCH YOUR HARDWARE 
#define SERIAL_BAUD_RATE    9600

//PIN 0 is D3 ON THE CHIP 
#define IR_PIN              0
    
    
/*---------------------------------------*/
//Runs once, when device is powered on or code has just been flashed 
void setup()
{
    //if set wrong, your serial debugger will not be readable 
    Serial.begin(SERIAL_BAUD_RATE);

    //initialize wifi connection 
    wifi = new WifiConnection(myWifiSsid, myWifiPassword);
    wifi->begin();

    //initialize the IR 
    irSend = new IRsend(IR_PIN, false);
    irSend->begin();

    //initialize wemo emulator 
    wemulator = new Wemulator();

    //connect to wifi 
    if (wifi->connect())
    {
        wemulator->begin(); 

        //start the wemo emulator (it runs as a series of webservers) 
        wemulator->addDevice("tv", new WemoCallbackHandler(&commandReceived));
        wemulator->addDevice("television", new WemoCallbackHandler(&commandReceived));
        wemulator->addDevice("my tv", new WemoCallbackHandler(&commandReceived));
        wemulator->addDevice("my television", new WemoCallbackHandler(&commandReceived));
    }
}


/*---------------------------------------*/
//Runs constantly 
void loop()
{
    //let the wemulator listen for voice commands 
    if (wifi->isConnected)
    {
        wemulator->listen();
    }
}

Pre-Testing

Test what we have so far (wifi and emulator), by running it with Alexa. This tutorial assumes that your Alexa device is set up and installed in your home.

Test discovery:

Say to Alexa, “Alexa, discover devices.”

This will cause Alexa to broadcast a UDP request on your local wifi network, scanning for Wemos and other compatible devices. This request should be received in the call to wemulator->listen(); in the loop() function. This in turn routes it to Wemulator’s handleUDPPacket(*) method. A response is sent out in the nextUDPResponse() method. Note the content of that response:

const char UDP_TEMPLATE[] PROGMEM =
    "HTTP/1.1 200 OK\r\n"
    "CACHE-CONTROL: max-age=86400\r\n"
    "DATE: Sun, 20 Nov 2016 00:00:00 GMT\r\n"
    "EXT:\r\n"
    "LOCATION: http://%s:%d/setup.xml\r\n"
    "OPT: \"http://schemas.upnp.org/upnp/1/0/\"; ns=01\r\n"
    "01-NLS: %s\r\n"
    "SERVER: Unspecified, UPnP/1.0, Unspecified\r\n"
    "ST: urn:Belkin:device:**\r\n"
    "USN: uuid:Socket-1_0-%s::urn:Belkin:device:**\r\n\r\n";

This is the code that tells Alexa “I’m a Wemo (Belkin), how can I help you?” Once Alexa receives this response, it knows and remembers that future smart-home commands may be routed to this device.

The output of the serial debugger at this point should look like the image below. When finished discovering, Alexa will verbally tell you that it has “discovered [N] devices” on your network.

Screenshot of Alexa output

In the setup() function, note the following snippet:

    new WemoCallbackHandler(&commandReceived)

This is the callback where we will capture commands from Alexa. Its body is defined in WemoCallbackHandler.h (WemoCallbackHandler::handleCallback). Once we’ve captured a command from Alexa, we can do what we like with it. In the lines before that, we’ve set up possible commands that can be used, with these lines of code:

    wemulator->addDevice("tv"); 
    wemulator->addDevice("television"); 
    wemulator->addDevice("my tv"); 
    wemulator->addDevice("my television");

So these are 4 separate “servers” or listeners we’re running on the chip. This sets up the ability to say any of the following commands to Alexa:

“Alexa, turn on tv”
“Alexa, turn off tv”
“Alexa, turn on television”
“Alexa, turn off television”
“Alexa, turn on my tv”
“Alexa, turn off my tv”
“Alexa, turn on my television”
“Alexa, turn off my television”

And this is how we’ll test it. We expect that saying any of those commands should wake up our code and enter that callback, where we can do what we like with it.

Screenshot of what happens when you say a command

Add the IR Command

Now that we’re receiving the command, it’s time to handle it by… turning on/off our TV. So this will be everything—wifi, wemo emulator, and IR—all put together. My TV is an LG, so I looked up the appropriate sequence for turning on/off, and sent that through our IR library’s sendNEC function (LG uses the NEC protocol). IR encoding/decoding is a separate subject in itself, wherein a message is encoded in the modulation of a signal; it’s a specification of very precise timings, marks, and spaces. Each manufacturer tends to use its own proprietary protocol for commands, and with different timings; it’s quite interesting, and you can dig deeper by looking into the source code of that IR library, googling, etc. But to our convenience, the details of all that are taken care of for us by our IR library.

Your TV’s not an LG? Just google the correct code. Here’s the command for Sony TVs (caveat: not tested):

irSend.sendSony(0xa90, 12);

If you want to get really do-it-yourself, you can set up an IR receiver, point your remote (or any IR transmitter) at it, and decode the codes that it’s sending; that’s a different tutorial, though.

End to End Test

  • Place your Alexa anywhere it can hear you.
  • Place your ESP8266 with attached IR diode, within remote-control range of the TV.
  • Say “Alexa, discover devices.” Wait for it to report success (it should have discovered at least one device).
  • Say “Alexa, turn on my TV” or “Alexa, turn off my TV.”

Alexa should understand your command (as a smarthome command, not directed to a specific skill), search for a local device to handle it, and send the command to the device (your ESP8266). Your device should receive it and send the remote control command to the TV. You can view your diode through a mobile phone camera to ensure that it’s emitting.

Since the IR code to turn a TV off is the same as the code to turn it on, it doesn’t matter whether you give the command to turn “on” or “off.” It’s the same code, and it toggles the state. If the TV’s off, it should turn on, and if on, it should turn off.

Troubleshooting

Are you connected to the Wifi?

Did you enter the correct username/password into the correct variable values?

//SET YOUR WIFI CREDS 
const char* myWifiSsid = "***";
const char* myWifiPassword = "*******";

Are you getting a failure message, or any error through the serial debug port, when connecting to the Wifi?

Is your Wifi turned on, and can you connect to it via any other ordinary means?

Is your device being discovered by the Alexa?

Alexa will send out requests to discover devices when you say “Alexa, discover devices.”

Your Alexa must be configured and set up properly and connected to the same Wifi network as your ESP8266.

Look in Fauxmo.h. See the function Fauxmo::handle(). This is the first code that will run once the ESP8266 has heard the call. Put in debug messages to see if any code after

  if (len > 0) 
  { 

is running. If it’s not, then the command is not being received. If it is, then it appears that the command is being received, but not handled correctly. Follow the code from there to find out what the problem is.

Do you have many other discoverable devices on your network? Too many can cause discovery to run more slowly, or even to sometimes fail.

Is your device receiving the command?

When you issue the command “Alexa, turn my TV on,” execution should be entering your WemoCallbackHandler::handleCallback handler (in the WemoCallbackHandler.h file). If you haven’t done so, try outputting some debug message in there to ensure that it’s firing when you issue your command. Also, try ensuring that Alexa knows about your device by saying “Alexa, discover devices” before issuing your command. This step assumes that device discovery has succeeded.

Is the IR diode emitting?

As described before, when you think your device should be emitting, point your mobile phone’s camera at it and look at the diode through the camera. Though in real life you can’t see anything, through the camera it should appear as a normal light lighting up and flashing. If you see this, then it’s emitting… something.

Is the IR signal reversed?

Your IR diode may be wired in such a way that the signal is essentially reversed. Please bear with me on my explanation, as I’m not an electronics or wiring guy, but the result of wrong-wiring the diode will be that the IR light will be ON by default, but turned OFF when the IRSend library intends to turn it on. If this is the case, your IR light should be on (visible through the camera) by default, after the setup() code runs, but before anything else happens. If you were to comment out all code inside of loop(), you should see it remain on continually.

To see more clearly how to fix this, go into the libraries/IRemoteESP8266/src folder of the tutorial code. See the constructor:

IRsend::IRsend(uint16_t IRsendPin, bool inverted) : IRpin(IRsendPin),
    periodOffset(PERIOD_OFFSET)
{
    if (inverted)
    {
        outputOn = LOW;
        outputOff = HIGH;
    }
    else
    {
        outputOn = HIGH;
        outputOff = LOW;
    }
}

The “inverted” argument and the logic that handles it is what we’re talking about. If your wiring is inverted, the easiest solution is to make a small change in the code to allow for this (rather than rewiring… but if course you can do that if you prefer). Just change this line in AlexaTvRemote.ino:

    //initialize the IR 
    irSend = new IRsend(IR_PIN, false);

to

    //initialize the IR 
    irSend = new IRsend(IR_PIN, true);

Do you have the right remote control code and command?

If everything else seems to be going ok, but the TV’s just not obeying, it’s probably quite likely that something is wrong with the IR code. Try different function calls on that IR library interface (e.g., sendLG, sendPanasonic, sendSharp, etc.), or make sure that the one you’re using matches your hardware. It’s very unlikely that your TV’s hardware is not supported by that library, but I guess it’s technically possible.

Make sure that the code you’re sending is the right one for your hardware. You might have to do some digging on google to find the right one. If all else fails, there’s always the option of detecting the code that emits from your working remote, when you press the Power button—but that’s a different tutorial and requires different hardware.

Wrapping Up

Hopefully everything worked out for you. If so (and maybe even if not), this has been a good way to cut your teeth on several subjects at once:

  • Alexa
  • Embedded programming
  • The ESP8266 chip
  • The Arduino IDE

Also of course, you have the maybe slight convenience, of being able to turn on/off your tv by voice command.

Why the Hack?

Why is this a hack, and not part of the basic API for the Alexa? After learning how to develop my first Alexa skill, all I really wanted to know was “how can I just send a command directly from the Alexa to another device on the network?” It’s a shame that Amazon hasn’t exposed a full-fledged API for communication between the Alexa device and other objects on the local network, without going through the “skill” or “smart-home” paradigm (wherein everything must be sent to AWS before doing anything), but they just have not.

Try to Take It Further

Try a suite of remote control commands to more fully control your tv, such as changing the channel and controlling volume. Test the limits of the chip by seeing how many different commands you can listen for on one ESP8266 (hint: the number barely breaks double digits, without some very clever programming). If you’re good with hardware, try controlling other devices not through IR, by wiring them directly to ESP8266 chips; like lighting and such. Reinvent the wemo!

Understanding the Basics

How do IoT devices communicate?

IoT devices may communicate over networks using any standard server-to-server or client-server protocols, such as direct TCP, HTTP, TLS, web sockets, etc. They can also use local wifi, relying on UDP, TCP, or other protocols. It's also not uncommon for IoT devices to use IR signals for communication.

About the author

John R. Kosinski, Thailand
member since October 28, 2015
As a full-stack mobile developer, John has been developing since around 2000. Early on he did some C++, ASP, VB6, and other things but since .NET came out most of his work has been in .NET. His work experience up until 2009 was in the NYC and NYC area; since 2009, he's been living and working in Thailand. Currently, he's consulting remotely for US clients and working on iOS, Android, and IoT projects. [click to continue...]
Hiring? Meet the Top 10 Freelance Arduino Developers for Hire in November 2017

Comments

Laureano Martín Arcanio
Thanks for the article, this is awesome, this chip looks like a a really cost effective alternative to Arduino and raspberry for many applications.
John Kosinski
Yeah, the basis for its popularity seems to be its cheapness, combined with its small size and capabilities. It's nice to work with.
jgn
Sorry but i can't find the source files for the tutorial. I'm sure i'm missing something obvious but what's the link to download these?
comments powered by Disqus
Subscribe
The #1 Blog for Engineers
Get the latest content first.
No spam. Just great engineering posts.
The #1 Blog for Engineers
Get the latest content first.
Thank you for subscribing!
Check your inbox to confirm subscription. You'll start receiving posts after you confirm.
Trending articles
Relevant Technologies
About the author
John R. Kosinski
C# Developer
As a full-stack mobile developer, John has been developing since around 2000. Early on he did some C++, ASP, VB6, and other things but since .NET came out most of his work has been in .NET. His work experience up until 2009 was in the NYC and NYC area; since 2009, he's been living and working in Thailand. Currently, he's consulting remotely for US clients and working on iOS, Android, and IoT projects.