Low Cost Automation With ESP01

Introduction: Low Cost Automation With ESP01

About: Do you like technology? Follow my channel on Youtube and my Blog. In them I put videos every week of microcontrollers, arduinos, networks, among other subjects.

Today, we’ll discuss automation using ESP01 with 16 relays. This is a super cheap design model where you can multiply the modules and get up to 128 relays, as it is possible to put up to eight port expanders in this microcontroller.

In our circuit, you will have an application on a smartphone that communicates with the ESP01. It will have an expander with 16 ports, each connected to a relay. We also have a 3v3 adjustable source. We’ll therefore control a 16-channel relay module using ESP01 through the Android application, which I make available to you.

Teacher Notes

Teachers! Did you use this instructable in your classroom?
Add a Teacher Note to share how you incorporated it into your lesson.

Step 1: Tip to Remember

It is important to note, my friends, that I used this chip in a circuit called MCP23016. It’s also important for you to watch the video EXPANSOR OF IOS FOR ESP32, ESP8266 AND ARDUINO, in which I test the device and show that it works for these three types of boards.

Step 2: MCP23016

Here we have an image of the MCP23016, which is a chip with 28 pins. It’s important to mention there is also the MCP23017 model, which is more common and does not need a resistor and capacitor, because it has an internal clock. This makes it easier, but its pinning is different from what we show in this video.

Step 3: Address

To define the address of the MCP23016, we use pins A0, A1, and A2. You can just leave them at HIGH or LOW for the address change.

The address will be formed as follows:

MCP_Address = 20 + (A2 A1 A0)

Where A2 A1 A0 can take HIGH / LOW values, a binary number from 0 to 7 forms.

For example:

A2> GND, A1> GND, A0> GND (means 000, then 20 + 0 = 20)

Or otherwise,

A2> HIGH, A1> GND, A0> HIGH (means 101, then 20 + 5 = 25)

Step 4: Commands

Here is a table with commands for communication:

Step 5: Categories

GP0 / GP1 - Data Port Registers

There are two registers that provide access to the two GPIO ports.

The register reading provides the status of the pins on that port.

Bit = 1> HIGH Bit = 0> LOW


There are two registers that control the pin mode. (Input or Output)

Bit = 1> INPUT Bit = 0> OUTPUT

Step 6: Structure for Communication

Here we talk about the address of the chip, and access the command and data, which is a kind of protocol that needs to be done to send information.

Step 7: Program

We’ll do a program that consists of communicating the ESP01 with the MCP23016 in order to have more GPIOs to use. These 16 new GPIOs that we’ll have are going to control a 16-channel relay module.

Commands will be sent to ESP01 via an Android application.

Step 8: MCP23016

Step 9: ESP-01

This is a 16-relay board.

Step 10: Mounting ESP01

Step 11: Libraries and Variables

We will include the libraries responsible for i2c communication, and for creating the Access Point and webserver. We define the address of the chip and the ports. Finally, we define the variables to store the values of the MCP pins.

#include <Wire.h> // responsável pela comunicação i2c.
#include <ESP8266WiFi.h> //responsável por criar o accesspoint e o webserver WiFiServer server(80);//webserver para acessarmos através do aplicativo //endereço I2C do MCP23016 #define MCPAddress 0x20 //ENDEREÇOS DE REGISTRADORES #define GP0 0x00 // DATA PORT REGISTER 0 #define GP1 0x01 // DATA PORT REGISTER 1 #define IODIR0 0x06 // I/O DIRECTION REGISTER 0 #define IODIR1 0x07 // I/O DIRECTION REGISTER 1 // guarda os valores dos pinos do MCP uint8_t currentValueGP0 = 0; uint8_t currentValueGP1 = 0;

Step 12: Setup

We initialize the ESP01 and configure the ports. We also configure the Access Point and initialize the server.

void setup() {
Serial.begin(9600); delay(1000); Wire.begin(0,2); //ESP01 Wire.setClock(200000); configurePort(IODIR0, OUTPUT); configurePort(IODIR1, OUTPUT); writeBlockData(GP0, 0x00); writeBlockData(GP1, 0x00); setupWiFi(); //configuração do Access Point server.begin();//inicializa o server }

Step 13: Loop

Here I check if any clients have been connected to the server. We also read the first request line. We extract the data for manipulation, define the default response header, and send this response to the client.

void loop() {
WiFiClient client = server.available(); // Verifica se um cliente foi conectado if (!client) { return; } String req = client.readStringUntil('\r');// Faz a leitura da primeira linha da requisição /* /MR é o header prefixo para saber se a requisição é a esperada para os relés */ if(req.indexOf("/MR") != -1) { parserData(req); //a partir da requisição extrai os dados para manipulação } else{ Serial.println("invalid request"); return; } client.flush(); String s = "HTTP/1.1 200 OK\r\n"; // cabeçalho padrão de resposta client.print(s); // envia a resposta para o cliente delay(1); } // end loop

Step 14: ParserData

From the request, we look for the data related to the relays. We then send the data to the MCP23016.

//a partir da requisição busca os dados referente aos relés
void parserData(String data) { uint8_t relay = -1; uint8_t gp = -1; uint8_t value = -1; int index = data.indexOf("/MR"); //busca o index do prefixo MR if(data[index+5] == '/') // /MR01/1, onde 0 = GP; 1 = RELE; 1 = ESTADO(on/off) { gp = data[index+3]-'0'; relay = data[index+4]-'0'; value = data[index+6]-'0'; //envia os dados para o MCP23016 //[relay-1] porque o MCP vai de 0-7 os pinos writePinData(relay-1, value, gp); } }

Step 15: ConfigurePort

We set the GPIO pin mode (GP0 or GP1).

//configura o modo dos pinos GPIO (GP0 ou GP1)
//como parametro passamos: // port: GP0 ou GP1 // INPUT para todos as portas do GP trabalharem como entrada // OUTPUT para todos as portas do GP trabalharem como saida // custom um valor de 0-255 indicando o modo das portas (1=INPUT, 0=OUTPUT) // ex: 0x01 ou B00000001 ou 1 : indica que apenas o GPX.0 trabalhará como entrada, o restante como saida void configurePort(uint8_t port, uint8_t custom) { if(custom == INPUT) { writeBlockData(port, 0xFF); } else if(custom == OUTPUT) { writeBlockData(port, 0x00); } else { writeBlockData(port, custom); } }

Step 16: WritePinData

In this part of the code, we change the state of a desired pin and send the data to the MCP.

//muda o estado de um pino desejado, passando como parametro:
//pin = pino desejado; value = 0/1 (on/off); gp = 0/1 (PORT do MCP) void writePinData(int pin, int value, uint8_t gp) { uint8_t statusGP = 0; if(gp == GP0) statusGP = currentValueGP0; else statusGP = currentValueGP1; if (value == 0) { statusGP &= ~(B00000001 << (pin)); // muda o pino para LOW } else if (value == 1) { statusGP |= (B00000001 << (pin)); // muda o pino para HIGH } if(gp == GP0) currentValueGP0 = statusGP; else currentValueGP1 = statusGP; //envia os dados para o MCP writeBlockData(gp, statusGP); delay(10); }

Step 17: WriteBlockData & SetupWiFi

Here, we send data to the MCP23016 via the i2c bus. Next, we configure the properties to enable the Access Point. Finally, we configured the WiFi for Access Point mode and created an AP with SSID and the PASSWORD.

//envia dados para o MCP23016 através do barramento i2c
//reg: REGISTRADOR //data: dados (0-255) void writeBlockData(uint8_t port, uint8_t data) { Wire.beginTransmission(MCPAddress); Wire.write(port); Wire.write(data); Wire.endTransmission(); delay(10); }

//configura as propriedades para habilitar o ACCESS POINT
void setupWiFi() { WiFi.mode(WIFI_AP); WiFi.softAP("ESP01_RELAY", "12345678"); }

Step 18: App

To create the application, we use MIT App Inventor 2, which can be accessed through the link:


The application consists of two screens containing eight pairs of buttons in each, indicating the status of each relay.

The following are some of the programming blocks used:

IMPORTANT: The default IP address of the ESP, as the Access Point is

1. When the screen initializes, we store the IP in memory and call the procedure to recover the state of the buttons (ON / OFF).

2. Call the other screen

1. When clicking on the ON button of one of the relays, we will make visual changes in the button (green blocks). WebViewer1.GoToUrl makes a request for our ESP01 by linking the MR01 / 1 data in the URL.

2. When clicking the OFF button of one of the relays, we will make visual changes in the button (green blocks). WebViewer1.GoToUrl makes a request to our ESP01 by linking the MR01 / 0 data in the URL.

This procedure is used to recover the state of the buttons (relays), because when changing the screen, it returns to the creation pattern.

The yellow block repeats for each of the button pairs.

Step 19: Download

Here are the project files for download:

MIT App Inventor 2 project file - download

Application APK to install on android - download

Download the other files:



Be the First to Share


    • Backyard Contest

      Backyard Contest
    • Silly Hats Speed Challenge

      Silly Hats Speed Challenge
    • Arduino Contest 2020

      Arduino Contest 2020