ESP8266 – Salvando Credenciais Wi-Fi na EEPROM Através de um Access Point (AP)

Neste tutorial vamos mostrar como conectar seu ESP8266 a qualquer rede Wi-Fi de sua escolha sem a necessidade de alterar seu código cada vez que precisar utilizar uma rede diferente. Isso será realizado através da criação de um Ponto de Acesso que exibirá um formulário HTML ao usuário conectado à placa, seja por um computador ou smartphone.

Após a inserção das credenciais de sua rede, a placa ganhará acesso à internet e salvará os dados em sua memória interna para que não haja necessidade de o usuário digitar a senha da rede toda vez que ligar a placa.

Esta função pode ser reaproveitada para tentar uma reconexão à rede caso a placa perca acesso à internet.

Componentes necessários

Para seguir este tutorial, você precisará dos seguintes itens:

A programação do NodeMCU será feita através da IDE do Arduino. Caso não saiba como configurar a IDE para programar módulos baseados no ESP8266, recomendamos primeiro ler o seguinte tutorial:

ESP8266 – Como Programar o NodeMCU Através da Arduino IDE

ESP8266 Como Access Point

Vamos iniciar nosso projeto criando um Ponto de Acesso (AP) para nosso NodeMCU. Isso significa que a placa possuirá uma rede própria à qual o usuário poderá se conectar.

Começaremos com uma chamada à biblioteca de Wi-Fi do ESP8266:

Agora vamos definir um nome (SSID) e uma senha para nosso AP. Crie uma variável global para cada dado para facilitar sua alteração caso julgue necessário no futuro:

Os valores das strings acima podem ser alterados para qualquer valor de sua escolha.

Dentro do setup(), vamos inicializar a comunicação serial de nosso NodeMCU com o computador para que possamos imprimir dados da rede no monitor serial. Usaremos um baud rate (velocidade de transmissão de informação) de 115200:

Ainda no setup(), inicialize o AP utilizando as variáveis criadas anteriormente:

E imprima o IP de seu AP:

É importante saber qual endereço de IP sua placa está usando, pois você se comunicará com a placa através deste endereço. Por padrão, o ESP8266 possui o IP 192.168.4.1, mas é possível alterar este valor através de funções de configuração de AP.

Imagem 1 – IP e nome do AP

Imagem 1 – IP e nome do AP

ESP8266 Como Web Server

Após criarmos o AP de nosso ESP8266, precisamos que ele seja capaz de receber as credenciais da rede a qual você quer conectar a placa para que ela tenha acesso à internet. Logo, ele passará a agir como um servidor Web que receberá requisições do usuário, realizará um processamento delas e enviará respostas a partir de funções que criaremos em nosso código.

No topo de seu código, adicione a chamada:

Esta biblioteca é utilizada para criar servidores HTTP síncronos, onde o usuário vai interagir com uma interface Web através de um navegador, o navegador enviará requisições ao servidor e o servidor vai então responder exibindo no navegador uma nova página ao usuário. Este tipo de servidor suporta um único usuário por vez.

Antes de seguirmos para as configurações do servidor, devemos instanciar um objeto da classe como variável global, passando como argumento a porta HTTP padrão de número 80:

Dentro da função setup(), vamos agora configurar o servidor para receber requisições do usuário e direcioná-las a funções que criaremos mais à frente. Isso é realizado através do método on(URI, handlerFunction) do objeto que acabamos de criar. Este método possui dois parâmetros, sendo o primeiro a URI (parte do endereço de link que ficará após o IP do servidor) e o segundo o nome da função associada ao endereço.

A primeira função que criaremos ficará responsável pela raiz de nosso servidor. Será a primeira operação realizada quando o usuário digitar o IP da placa no navegador. Chamaremos esta função de handleRoot():

A segunda função será responsável por conectar a placa a uma rede Wi-Fi a partir dos dados digitados pelo usuário em um formulário que criaremos mais à frente. Vamos chamá-la de handleForm() e sua URI será /action_new_connection:

Em seguida, teremos uma função para que a placa possa se conectar a partir de informações salvas anteriormente em sua memória interna. Ele se chamará connectEeprom() e sua URI será /action_previous_connection:

Com todas as funções do servidor declaradas, vamos inicia-lo:

Por último, agora dentro da função loop(), devemos chamar o método handleClient() para que seja possível processar as requisições do usuário:

HTML

Para exibir uma interface de conexão ao usuário, vamos precisar criar uma página HTML. No NodeMCU podemos fazer isso de duas maneiras: a primeira é fazendo upload de um arquivo HTML para a placa (o que exige configuração adicional da IDE do Arduino) e a segunda é criando uma String que receberá todo o código de sua página HTML. Neste tutorial vamos optar pela segunda.

Nossa interface terá apenas um formulário simples através do qual o usuário enviará as credenciais da rede Wi-Fi para o ESP8266. Ele possuirá três estruturas básicas:

  • Um <select>, uma espécie de dropdown menu que exibirá todas as redes ao alcance do NodeMCU;
  • Um <input> do tipo password, que nada mais é do que uma caixa de texto onde as informações digitadas pelo usuário são convertidas em asteriscos;
  • Dois botões, sendo um deles um <input> do tipo button e outro um <button> contendo um link.

Ao clicar no <input> – de nome “Conectar” – será chamada uma função JavaScript que fará a validação dos dados antes de enviá-los para o ESP8266. Caso o usuário deixe um dos campos vazios, será exibida uma mensagem de erro como mostrada na imagem abaixo:

Imagem 2 – Caso um dos campos esteja vazio, é exibida uma mensagem de erro

Imagem 2 – Caso um dos campos esteja vazio, é exibida uma mensagem de erro

O segundo botão – uma tag <button> – visto na imagem servirá para conectar o NodeMCU a partir de dados previamente salvos em sua memória interna. Veremos mais à frente como ele funcionará.

Nosso HTML será inserido no código através de uma variável global do tipo vetor de caracteres que será armazenada e lida diretamente da memória de programa (Flash) do NodeMCU em vez da SRAM, onde seria normalmente armazenada. Isso é indicado pelo modificador PROGMEM. Faremos isso para que exista sempre uma cópia inalterada da página disponível no nosso programa sem ocupar o espaço dedicado à sua execução.

Note que nosso código CSS está embutido na tag <head> de nosso HTML para melhorar a aparência da página.

Processando Requisições no ESP8266

Vamos agora criar as funções handleRoot() e handleForm() que definimos anteriormente para o nosso web server.

O propósito desta primeira será apenas exibir nossa interface de conexão para o usuário. Porém, antes de fazer isso devemos buscar por todas as redes Wi-Fi ao alcance do NodeMCU para que nosso <select> não fique vazio no HTML. Será então criada uma função que chamaremos de listSSID() para realizar essa tarefa.

Listando Redes Wi-Fi Próximas

Começaremos recuperando nosso HTML da memória Flash, pois vamos precisar edita-lo:

Em seguida, chamaremos a função WiFi.scanNetworks() que nos retornará a quantidade de redes disponíveis. Vamos armazenar este valor em uma variável do tipo int:

Esta operação também armazena dentro do objeto WiFi informações como SSID e potência de sinal de todas as redes encontradas.

Agora que temos a quantidade de redes próximas e suas informações, podemos chamar o método WiFi.SSID() dentro de um laço de repetição para adicionar o nome de todas as redes ao nosso HTML. Este método recebe como argumento o índice de cada uma das redes dentro de uma lista criada dentro do objeto.

Aplicaremos o método replace() na String que contém nosso HTML. Para preencher o <select> com os SSIDs das redes.

Nossa função listSSID() ficará assim:

Dentro da função handleRoot(), faremos uma chamada à listSSID() armazenando seu resultado em uma String que será então enviada para o usuário. Para isso, é usado o método send() de nosso servidor. Ele possui três parâmetros: status message, tipo de conteúdo e por último o conteúdo em si – no caso, nossa String.

Recebendo Dados do Formulário

Agora vamos criar a função handleForm() que processará os dados informados pelo usuário.

Voltando ao nosso HTML, vemos que tanto nosso <select> quanto nosso <input> do tipo “password” possuem atributos chamados “name” (“nome” em inglês).

Estes “nomes” são utilizados para identificar cada campo do formulário para que seus valores possam ser acessados pelo NodeMCU através do método arg() de nosso servidor. Vamos armazenar estes valores em variáveis, nos certificar de que os campos não estão vazios e então enviar os dados para uma nova função que chamaremos de connectToWiFi().

Antes de seguirmos para esta função, vamos criar no topo do código – abaixo da inclusão de bibliotecas – uma macro que corresponderá ao LED embutido na placa, conectado ao pino D4:

Conectando à Rede Wi-Fi

Dentro de connectToWiFi(), passaremos as credenciais da rede para o método WiFi.begin(), que é responsável por conectar o NodeMCU à rede Wi-Fi.

Vamos então criar um laço de repetição que vai esperar pelo resultado desta operação, verificado pelo método WiFi.status(). Caso a conexão ocorra normalmente, vamos acender o LED, exibir o endereço IP do dispositivo no monitor serial e enviar uma nova página ao usuário contendo uma mensagem de sucesso. Caso contrário, será enviada uma página com uma mensagem de erro.

Imagem 3 – Mensagem de sucesso

Imagem 3 – Mensagem de sucesso

Imagem 4 – Mensagem de erro

Imagem 4 – Mensagem de erro

Caso tenha problemas para receber o resultado da operação (timeout), teste diminuir o número de iterações do laço de repetição.

EEPROM do ESP8266

A EEPROM (Electrically-Erasable Programmable Read-Only Memory) é um tipo de memória não-volátil utilizada para armazenar pequenas quantidades de dados que não são perdidos após o desligamento do dispositivo. Ela é muito útil para salvar dados de configuração, credenciamento de usuários ou leituras de sensores por exemplo. Neste projeto, vamos usá-la para salvar a última rede a qual o NodeMCU se conectou para que não seja necessário o usuário inserir novamente o nome da rede e sua senha toda vez que ligar o dispositivo. A reconexão poderá ser realizada através de um simples clique de botão.

O ESP8266 possui uma biblioteca padrão utilizada para a manipulação da EEPROM. Para iniciá-la, basta adicionar a seguinte chamada ao topo de seu código:

Salvando Dados

Para salvar as credenciais da rede Wi-Fi, vamos criar uma função chamada salvarEeprom() que terá como parâmetros o nome e a senha da rede:

Diferente das placas Arduino, o ESP8266 não possui uma memória EEPROM real. Ela é emulada utilizando uma sessão de sua memória Flash. Por isso, no ESP8266 é necessário informar durante a inicialização da EEPROM a quantidade de bytes que serão utilizados. Isso acontece através da função EEPROM.begin(size), que aceita valores de 4 a 4096 bytes. Para este tutorial, vamos usar 98 bytes:

A EEPROM pode ser interpretada como um array (vetor) de bytes, com cada posição dela sendo 1 byte. Isso significa que em cada posição de nossa EEPROM poderemos armazenar uma única variável do tipo char (caractere), totalizando 98 caracteres quando ocupada por completo.

Sabemos que 1 único byte também pode representar valores numéricos de 0 a 255, logo, vamos reservar as duas primeiras posições da EEPROM para armazenar dois valores numéricos que indicarão os tamanhos (quantidade de caracteres) do SSID e da senha. Estes valores serão usados para dizer ao programa quantas posições cada uma destas informações está ocupando na memória e possibilitar a leitura dos dados de forma independente.

Para salvar dados na EEPROM, precisamos chamar a função EEPROM.write(address, value), onde address é o índice (de 0 a 97) e value será nossa variável de tamanho. Como estamos usando objetos do tipo String para representar o SSID e a senha, podemos usar o método length() da classe String para pegar os seus tamanhos. Sendo assim, temos:

Em seguida, criaremos dois laços de repetição para armazenar as credenciais na memória:

Ao final, é necessário chamar a função EEPROM.commit() para assegurar que as mudanças sejam salvas na memória Flash e a função EEPROM.end() para encerrar as operações na EEPROM.

Com a biblioteca EEPROM padrão do ESP8266, a memória Flash é reprogramada toda vez que os dados da EEPROM são gravados, o que pode desgasta-la rapidamente. Para evitar operações desnecessárias na Flash, vamos adicionar uma condição para que os dados sejam salvos: a operação só será realizada caso os dados informados pelo usuário sejam diferentes daqueles já presentes na memória. Isso será verificado por uma função que chamaremos de compareEeprom().

Nossa função salvarEeprom() ficará assim:

Comparando Dados da Memória EEPROM

Em nossa função compareEeprom() serão realizadas operações apenas de leitura, o que não prejudicará a integridade da Flash. Caso o valor lido seja igual ao recebido pelo usuário, a função retornará true e não salvará nada na EEPROM. Caso o valor lido seja diferente do recebido, a função retornará false e os dados presentes na EEPROM serão substituídos.

Para ler uma informação da memória, usamos a função EEPROM.read(address), onde address é a posição a ser lida. Lembrando que as duas primeiras posições são valores numéricos que não fazem parte das credenciais do Wi-Fi, a função compareEeprom() ficará assim:

Conexão Através da EEPROM

Nossa última função de acesso à EEPROM será a que realiza a conexão Wi-Fi a partir dos dados armazenados na memória, sendo chamada pelo usuário ao clicar no botão “Conectar à Última Rede Utilizada.” Ela vai se assemelhar bastante à função compareEeprom(), mas ao invés de retornarmos um valor booleano, ao final da função vamos fazer uma chamada à função connectToWiFi() passando como parâmetros os valores de SSID e senha lidos da EEPROM. Chamaremos essa função de connectEeprom():

Código do ESP8266

Aqui está o código completo pronto para ser carregado para sua placa:

 

Gostou? Deixe seu comentário logo abaixo, não deixe de conferir outras postagens do nosso blog. Confira também a nossa loja virtual e encontre todos os componentes utilizados no projeto no post.

Gabriel Martins de Freitas

Graduando em Sistemas e Mídias Digitais. Tenho experiência com Arduino e ESP8266. Atualmente compartilhando meu conhecimento no blog da Smart Kits.

Post navigation

2 Comentários

  • Gabriel,

    estava a um tempo procurando uma solução para esse problema, de ter as credenciais da rede wifi no código, hoje estava desenvolvendo algo para gravar e ler na eprom, até que encontrei esse seu link.

    Fou sucesso! Resolveu meu provlema 100%. Agora posso até criar um produto comercial, onde posso entregar o embarcado para o cliente configurar.

    Parabéns!

  • Bom dia.
    Segui todos os parametros indicados (ESP8266 NodeMCU 12), gravei o sketch.
    Funcionou como o indicado porem não está gravando na EEPROM.
    Ao dar RESET ele volta com 192.168.4.1 e não acessa WiFi local.
    Qualquer dica será bem vinda.
    Abraços.
    INFORMAÇÕES:
    IDE Arduino 1.8.16
    Placa: NodeMCU 1.0 (ESP-12E Module)
    Flash Size:4MB(FS:2MB OTA:~1019KB)
    VTables:”Flash”
    Stack Protection: Disable
    Erase Flash:”Only Sketch”
    SSL Support: All SSL ciphers (most compatible)
    MMU: 32KB cache+32KB RAM(balanced)
    Non-32-Bit Access

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *

Blynk – Medição de temperatura com DS18B20

Blynk IoT – Monitoramento com ESP8266 e Sensor de Umidade do Solo (Higrômetro)

Primeiros passos com o Arduino Mega WiFi