Introduction: Arduino Mega + WiFi = Automation

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, I’ll talk about an assembly that was suggested by many followers: Arduino Mega + ESP. This will include an automation project with 16 relays, three sensors, and a smartphone. We’ll make a Web Server for the Arduino Mega using serial communication with the ESP8266, in the ESP-01 version. I will also show a page with the values of sensors and buttons to modify the state of the relays.

Step 1: Assembly

I placed here the schematic, which shows the DHT22, the Ds18b20, and a third sensor (the light), which are all connected to the relays by the pins 36 to 51.

Step 2: Demonstration

See the video demonstration of the project in operation. In the assembly, you are given a 16-wire board, which is connected directly to the ports of an Arduino Uno. This Uno I used was only to power the 3v3 of the ESP-01. I still have an LDR (which is my light sensor), a Ds18b20 thermometer, and the DHT22, which collects humidity and temperature data. We have an application on the smartphone that will display the data collected by these sensors and send them to the cell phone from the Arduino Mega, through the ESP, which would be the serial bridge (ie the WiFi).

In the assembly, we have LEDs which, when lit, indicate that the respective relays are switched off. This process is also controlled by the smartphone.

Step 3: Libraries

For our project today, we will need certain libs:

WiFiEsp Library

In the Arduino IDE, go to Sketch-> Include Library-> Manage Libraries ...

Install WiFiEsp

DallasTemperature Library

In the Arduino IDE, go to Sketch-> Include Library-> Manage Libraries ...

Install DallasTemperature

OneWire Library

In the Arduino IDE, go to Sketch-> Include Library-> Manage Libraries ...

Install OneWire

DHT sensor library by Adafruit

In the Arduino IDE, go to Sketch-> Include Library-> Manage Libraries ...

Install DHT sensor library by Adafruit

Step 4: Source Code


We start off by including the libraries and defining the pins attached to the sensors. We also point out the pin where the first relay will be and how many pins (starting from this first one) will be used.

#include <OneWire.h>
#include <DallasTemperature.h> #include <DHT.h> #include <WiFiEsp.h> //Pinos onde estão os sensores #define PIN_DS18B20 7 #define PIN_DHT22 8 #define PIN_LUMINOSITY A0 #define FIRST_PIN 36 //Pino onde está o primeiro relê #define PINS_COUNT 16 //Quantos pinos a partir do primeiro serão utilizados

We continue with the DS18B20 temperature sensor, and the DHT22 temperature and humidity sensor. We then set out for definitions involving the WiFi network, such as the SSID and password for the ESP to connect. We point to the server that will receive the requests on port 80 (standard port http), as well as the variables to store the values of the sensors.

//Sensor de Temperatura DS18B20
OneWire oneWire(PIN_DS18B20); DallasTemperature sensors(&oneWire); DeviceAddress sensor; //Sensor de temperatura e umidade DHT22 DHT dht(PIN_DHT22, DHT22); //SSID e senha da rede wifi para o ESP se conectar char ssid[] = "SSID"; char pass[] = "12345678"; char ip[] = ""; //Servidor que receberá as requisições na porta 80 (porta padrão http) WiFiEspServer server(80); //Variáveis para armazenar os valores dos sensores float temperatureDS18B20 = 0; float temperatureDHT22 = 0; float humidityDHT22 = 0; int luminosity = 0; //Mantém o estado atual dos pinos (HIGH ou LOW) int pinsStatus[PINS_COUNT];

MEGAESP_01.ino - setup

We initialize the serial and serial monitor where the ESP-01 is with AT firmware, in addition to pins, and DS18B20 and DHT22 sensors. For the brightness sensor, we just need to read the analog pin. We also initialize the WiFi and connect to the network. Finally, we initialize the server.

void setup()
{ //Serial para o monitor serial Serial.begin(115200); //Serial onde está o ESP-01 com firmware AT Serial1.begin(115200); //Inicializa os pinos setupPins(); //Inicializa o sensor DS18B20 setupDS18B20(); //Inicializa o sensor DHT22 dht.begin(); //Para o sensor de luminosidade apenas precisamos ler o pino analógico pinMode(A0, INPUT); //Inicializa WiFi e conecta à rede setupWiFi(); //Inicializa o server server.begin(); }

MEGAESP_01.ino - setupPins

In this step, we put the pins that are connected to the relays as outputs.

void setupPins()
{ //Coloca os pinos que estão ligados os relês como saída for(int i=0; i

MEGAESP_01.ino - setupWiFi

Here, we perform a function that initializes the serial where the ESP-01 is with the AT firmware already installed. We wait to connect to the WiFi network, configure the IP, and verify the same IP.

void setupWiFi()
{ //Serial onde está o ESP-01 com o firmware AT já instalado WiFi.init(&Serial1); Serial.print("Conectando a "); Serial.println(ssid); int status = WL_IDLE_STATUS; //Aguarda conectar à rede WiFi while (status != WL_CONNECTED) { status = WiFi.begin(ssid, pass); } Serial.println(); Serial.println("Conectado"); //Configura o IP IPAddress ipAddress; ipAddress.fromString(ip); WiFi.config(ipAddress); //Veririca o IP IPAddress localIP = WiFi.localIP(); Serial.print("IP: "); Serial.println(localIP); }

MEGAESP_01.ino - setupDS18B20

Initialize the DS18B20 sensor.

//Inicializa o sensor DS18B20
void setupDS18B20() { sensors.begin(); if (!sensors.getAddress(sensor, 0)) { Serial.println("Sensor não encontrado!"); } }

MEGAESP_01.ino - Loop

In the Loop, we check for a new client. We read the request and, if the request is not for the favicon, we execute the action with the value passed in the request. We then read the sensors and send the response to the customer. We determine a time for the browser to receive the data and close the connection with the client.

void loop()
{ WiFiEspClient client = server.available(); //Verifica se há um novo cliente if (client) { Serial.println("Novo cliente conectou"); //Faz a leitura da requisição char* request = readRequest(client); //Se a requisição não for para o favicon if(strstr(request, "favicon") == NULL) { //Executamos a ação com o valor passado na requisição execute(getAction(request), getValue(request)); //Faz a leitura dos sensores readSensorDS18B20(); readSensorDHT22(); readSensorLuminosity(); //Envia a resposta ao cliente sendResponse(client); //Tempo para o navegador receber os dados delay(100); } //Fecha a conexão com o cliente client.stop(); } }

MEGAESP_01.ino - readRequest

Here, we have a very important function. What does it do? When we press a button on the smartphone, the function sends the command in HTTP to ESP8266, using only the first line, as you see in the example below. I emphasize that even after reading the first line, it is important to read it until the end, otherwise the WiFiESP lib gives a timeout.

GET /?on=1 HTTP/1.1\r\n


Connection: keep-alive\r\n

Cache-Control: max-age=0\r\n

Upgrade-Insecure-Requests: 1\r\n

User-Agent: Mozilla/5.0 (Linux; Android 8.0.0; SM-G955F Build/R16N ) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.91 Mobile Safari/537.36\r\n

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8\r\n


Accept-Encoding: gzip, deflate\r\n

Accept-Language: en-US,en;q=0.9\r\n


Here, we have the reading of the first line of the request.

//Faz a leitura da primeira linha da requisição
char* readRequest(WiFiEspClient client) { bool currentLineIsBlank = true; char request[50]; int i = 0; bool firstLine = true; while (client.connected()){ if(client.available()){ char c =; Serial.write(c); //Apenas a primeira linha da requisição nos interessa if(firstLine){ request[i] = c; i++; }

We see that the last line of the request is: \ r \ n alone, \ r \ n. And, after the previous line, it is: \ r \ nso. If we get here, it is because the request has been read in full. Also, if you read any character other than \ n and \ r, it means that the line is not blank.

if (c == '\n'){
//A última linha da requisição é um \r\n sozinho, após o \r\n da linha anterior if(currentLineIsBlank){ //Se chegou aqui é porque a requisição foi lida por completo break; } currentLineIsBlank = true; firstLine = false; } else if (c != '\r'){ //Se leu qualquer caracter que não for \n e \r significa que a linha não está em branco currentLineIsBlank = false; } } } return request; }

MEGAESP_01.ino - sendResponse

This function sends the HTML to the client. It also sends the HTTP header, as well as the HTML header and body.

//Envia o HTML para o cliente
void sendResponse(WiFiEspClient client) { //Envia o cabeçalho HTTP client.print( "HTTP/1.1 200 OK\r\n" "Content-Type: text/html; charset=UTF-8\r\n" "Connection: close\r\n" "Refresh: 10; URL=/\r\n" //Para fazer requisação a raiz do server a cada 10 segundos "\r\n"); client.println("<!DOCTYPE HTML>"); client.println("<html>"); head(client);//Envia o cabeçalho do HTML body(client);//Envia o corpo do HTML client.println("</html>");


MEGAESP_01.ino - head

We sent the CSS to modify the appearance of the page.

//Envia o CSS para modificar a aparência da página
void head(WiFiEspClient client) { client.println(F("<head>" "<style>"


"text-align: center;" "font-family: sans-serif;" "font-size: 14px;" "}" "p{" "color:#555;" "font-size: 12px;" "}" ".button{" "outline: none;" "display: block;" "border: 1px solid #555;" "border-radius:18px;" "width: 150px;" "height: 30px;" "margin: 10px;" "margin-left: auto;" "margin-right: auto;" "cursor: pointer;" "}" ".button_off{" "background-color:#FFF;" "color: #555;" "}" ".button_on{" "background-color:#2C5;" "color: #fff;"



"</head>" ));


MEGAESP_01.ino - body

We then proceed to display the sensor data and create the buttons for each pin that has a relay.

//Exibe os dados dos sensores e cria os botões
void body(WiFiEspClient client) { client.println( "<body>" "DS18B20 Temperature: " + String(temperatureDS18B20) + " °C" " " "DHT22 Temperature: " + String(temperatureDHT22) + " °C" " " "DHT22 Humidity: " + String(humidityDHT22) + "%" " "); String buttons = ""; //Cria um botão para cada pino que possui um relê for(int i=0; i<PINS_COUNT; i++)






MEGAESP_01.ino - button

We create a button with the appearance and action that corresponds to the current state of the relay.

//Cria um botão com a aparência e ação correspondente ao estado atual do relê
String button(int number) { String label = String(number + 1); String className = "button "; className += pinsStatus[number] == HIGH ? "button_on" : "button_off"; String action = pinsStatus[number] == HIGH ? "off" : "on"; return "<button class=\"" + className + "\"onclick=\"location.href='?" + action + "=" + label +"'\">" + label + "<button>";


MEGAESP_01.ino - sensors

We read the DS18B20, DHT, and brightness sensors.

//Faz a leitura do sensor DS18B20
void readSensorDS18B20() { sensors.requestTemperatures(); temperatureDS18B20 = sensors.getTempC(sensor); } //Faz a leitura do sensor DHT void readSensorDHT22() { humidityDHT22 = dht.readHumidity(); temperatureDHT22 = dht.readTemperature(); } //Faz a leitura do sensor de luminosidade void readSensorLuminosity() { luminosity = analogRead(PIN_LUMINOSITY); }

MEGAESP_01.ino - getAction getValue

We return the action that the client wants to execute (on / off), as well as the value (number of the relay) of the action that will be executed.

//Retorna a ação que o cliente deseja executar (on off)
String getAction(char *request) { return getStringBetween(request, '?', '='); } //Retorna o valor (numero do relê) que a ação será executada String getValue(char *request) { return getStringBetween(request, '=', ' '); }

MEGAESP_01.ino - getStringBetween

We continue, this time, returning the string that lies between the first “start” character and the first “end” character. We return the memory address of the "start" character. If it does not find the character, it goes to the next one, until it reaches the "end" character or the end of the string.

//Retorna a string que fica entre o primeiro caractere 'start' e o primeiro caractere 'end'
String getStringBetween(char *input, char start, char end) { String str = ""; //retorna o endereço de memória do caractere 'start' char *c = strchr(input, start); //Se não achou o caractere if(c == NULL) { return ""; } //Vai para o próximo caractere c++; //Enquanto não chegar ao caractere 'end' ou ao final da string while(*c != end && *c!='\0') { str += *c; c++; } return str; }

MEGAESP_01.ino - execute

Finally, executed in the action next to the value (number of the relay), we observe if it is one of the two actions that we expect (On or Off). The relays are numbered from 1, but the array starts from 0. Then we draw 1.

The pin number will be the index plus the pin number where the relays start. The relays must be in sequence from the starting pin.

//Executada a ação junto ao valor (número do relê)
void execute(String action, String value) { //Se é uma das duas ações que esperamos if(action == "on" || action == "off") { //Os relês são numerados a partir do 1, max o array começa do 0 //então tiramos 1 int index = value.toInt() - 1; //O número do pino será o índice mais o número do pino onde os relês //começam. Os relês devem estar em sequência a partir do pino inicial (FIRST_PIN) int pinNumber = FIRST_PIN + index; int status = action == "on" ? HIGH : LOW; digitalWrite(pinNumber, status); pinsStatus[index] = status; } }

"         "body{"             "text-align: center;"             "font-family: sans-serif;"             "font-size: 14px;"         "}"         "p{"             "color:#555;"             "font-size: 12px;"         "}"         ".button{"             "outline: none;"             "display: block;"             "border: 1px solid #555;"             "border-radius:18px;"             "width: 150px;"             "height: 30px;"             "margin: 10px;"             "margin-left: auto;"             "margin-right: auto;"             "cursor: pointer;"         "}"         ".button_off{"             "background-color:#FFF;"             "color: #555;"         "}"         ".button_on{"             "background-color:#2C5;"             "color: #fff;"         "}"     "

Step 5: Files

Download the files: