A parte mais interessante na utilização do NodeMcu é criar um web server para dar comandos à distância para a plaquinha. Dessa forma, nós podemos criar nossos próprios dispositivos IoT. Portanto, neste post, vamos aprender a criar um web server utilizando um arquivo HTML para exibir informações básicas.

Na aula anterior, aprendemos a executar duas coisas ao mesmo tempo utilizando o modulo tmr.


O que é um Web server

Um Web Server ou servidor web nada mais é do que um servidor que se comunica por meio do protocolo HTTP. O HTTP é apenas um padrão utilizado para esse tipo de comunicação servidor-cliente. A imagem abaixo mostra o exemplo de uma mensagem.

Exemplo de uma mensagem com protocolo HTTP

Normalmente e também no nosso caso, a resposta do servidor é uma página na internet. Essa página é simplesmente um arquivo HTML. HTML é um tipo de linguagem (código) utilizado para representar textos e mídias (entre outros elementos especiais). As imagens abaixo mostram: o exemplo de um código em HTML e a sua representação em um navegador.

Código em HTML

Representação do código em HTML

E, para acessar esses dados, geralmente nós (clientes) utilizamos um navegador de internet. Podemos também fazer essa comunicação por meio de um aplicativo de celular ou por um software de computador. Essas são as formas mais interessantes de se utilizar dispositivos IoT. No geral, será interessante criarmos uma página com botões para comandar dispositivos ligados no NodeMcu e com textos para mostrar a leitura de sensores.

Quem tiver interesse de aprender sobre o funcionamento da linguagem HTML (muito importante para criar um Web Server), recomendo o site w3schools. Com ele você pode aprender rapidamente os diferentes elementos de um código em HTML. É interessante aprender sobre CSS também, que é uma linguagem útil para descrever o estilo dos elementos HTML. Garanto que é um assunto bem tranquilo de aprender.


Como criar

Antes de adentrarmos na criação do web server, vale mencionar que o NodeMcu possui uma certa limitação quanto ao envio de dados. De acordo com testes que realizei, acontecem erros ao enviar códigos em HTML que tenham mais de 2900 caracteres (valor aproximado), cerca de 77 linhas no meu caso. Erros esses que impediam a visualização correta da página.

Conectando em uma rede

A primeira coisa a ser feita, é conectar o NodeMcu em uma rede wi-fi. Pois é por meio dessa rede que nós podemos acessá-lo. E, para fazer isso é bem simples, basta utilizar algumas funções básicas do módulo wifi:

1
2
wifi.setmode(wifi.STATION)
wifi.sta.config({ssid="NOME_DO_SEU_WI-FI", pwd="SENHA_DO_WI-FI"})

O primeiro comando configura o NodeMcu para operar no modo “estação”. Este modo apenas habilita ele a conectar em um wi-fi e usufruir de suas utilidades. A titulo de curiosidade, existem outros dois modos: um chamado access point, que faz ele virar um roteador; e outro que ele faz as duas coisas (estação e access point).

Uma funcionalidade interessante de adicionar neste ponto é um timer que aguarda o NodeMcu se conectar à rede e mostra seu IP. É útil saber o IP, pois é por ele que nós acessaremos a página criada pela plaquinha. Para criar o timer, é só utilizar o modulo tmr que foi mostrado na aula anterior.

1
2
3
4
5
6
7
8
9
tmr.alarm(0, 1000, 1, function() --Aguarda o esp conectar na rede
   if wifi.sta.getip() == nil then
      print("Conectando à rede...\n")
   else
      ip=wifi.sta.getip()
      print("IP: ", ip)
      tmr.stop(0)
   end
end)

O código acima criar um alarme que dispara a cada 1 segundo. E, toda vez que ele dispara, o programa verifica se o NodeMcu já possui um IP. Se sim, ele exibe o ip na tela e para o timer. Veja o resultado na imagem abaixo:

NodeMcu conectando no wi-fi

Apenas com o código atual, caso eu tente me conectar no IP informado (colocar na barra de endereço do navegador), nada acontece. Isso porque, o NodeMcu ainda é apenas um dispositivo qualquer conectado na rede.

Existem outras formas de configurar a rede. Então, se tiver interesse, recomendo ler a documentação do modulo.

Criando servidor

Para criar o web server, nós utilizaremos o modulo net. O módulo net permite criar tanto um servidor quanto um cliente. E, para criar o servidor, utilizamos o seguinte comando:

srv = net.createServer(net.TCP)

Não se preocupe com o parâmetro net.TCP, ele apenas indica o protocolo de comunicação a ser utilizado. Agora, srv representa nosso servidor e podemos então fazer algumas coisas com ele. Podemos utilizar o comando listen para ficar “ouvindo” constantemente e verificar se algum IP tentou se comunicar com o NodeMcu. Vou mostrar o código completo e explicá-lo em detalhes:

Código retirado do site do NodeMcu.

1
2
3
4
5
6
7
srv=net.createServer(net.TCP)
srv:listen(80, function(conn)
    conn:on("receive",function(client,payload)
        print(payload)
        client:send("<h1> Hello, NodeMcu.</h1>")
    end)
end)

Com o servidor criado, nós ficamos esperando alguma conexão com o comando listen. O parâmetro 80 é a porta associada a função. Caso a conexão seja bem sucedida, a função dentro do comando listen é executada. Após isso, nos utilizamos outro comando chamado on para verificar se um determinado evento irá ocorrer. “conn” é justamente a conexão, e nós utilizamos o comando “on” para verificar quando um determinado evento desta conexão irá ocorrer.

No caso, o evento foi o “receive” que é quando o NodeMcu recebe alguma informação. Portanto, caso ele receba, a função dentro do comando “on” é executada. Essa função possui dois parâmetros atribuidos: client que é a comunicação que foi feita; e payload que são os dados recebidos pelo NodeMcu. Feito isso, nós exibimos na tela as informações recebidas e enviamos o seguinte dado: <h1> Hello, NodeMcu.</h1>.

Esse dado é um código em HTML. Se você não sabe o que significa, é basicamente um cabeçalho/título escrito “Hello, NodeMcu”. Portanto, nós podemos criar a nossa página nesta parte do código. É preciso apenas enviar todo nosso código HTML utilizando o comando client:send(). Por exemplo:

1
2
3
client:send("<h1>Central de controle dos LEDs</h1>")
client:send("<p> Apague e acione os LEDs facilmente.</p>")
client:send("<p> Basta apertar os botões.</p>")

Basta ser criativo e criar sua própria página HTML para sua aplicação. Os comando acima criam a seguinte página:

Página de exemplo

Obs: O comando de printar as informações recebidas (print(payload)) exibe a seguinte mensagem: (A mesma que coloquei no inicio do post)

Exemplo de uma mensagem com protocolo HTTP

Uma coisa muito importante que você precisa saber é que, é necessário resetar a plaquinha toda vez que fizer um ajuste no servidor e quiser fazer upload do código. Isso pois, o servidor fica em funcionamento e, ao fazer o upload do código, ele continua em segundo plano. Então, resetando a plaquinha, o servidor é finalizado. E assim, você pode fazer o upload do código para a nova versão ser iniciada.

Obs: Para acessar o webserver é só digitar o IP no navegador.

Finalizando conexão

Com o código que mostrei, o web server já funciona perfeitamente. Porém, faltou ele encerrar a conexão com o cliente. Para fazer isso, basta utilizar o seguinte comando depois de ter enviado os dados para o cliente:

client:on(“sent”, function(conn) conn:close() end)

Novamente, temos o comando on, desta vez aguardando o evento “sent”. Ou seja, quando os dados terminarem de ser enviados, a função associada ao comando é executada. No caso, a função associada é justamente para fechar a conexão – conn:close(). Com esta alteração, você poderá reparar que o navegador não fica carregando a página infinitamente (símbolo de recarregar do navegador não fica com X).

Imagens

Para exibir imagens na página, encontrei apenas uma forma viável, que é de usar links de imagens hospedadas na internet. Fazer upload do arquivo para dentro do NodeMcu não funcionou, porque o servidor não é capaz de encontrar o arquivo. E, codificar a imagem em base64 faz o NodeMcu travar devido ao extenso código de algumas imagens.

Portanto, para utilizar a solução que funciona, basta ir no Google e pesquisar a imagem desejada. Feito isso, clique com o botão direito e selecione “abrir imagem em uma nova guia”. Quando a nova guia for aberta, copie o link. Por exemplo, aqui do meu próprio site, eu peguei uma imagem e copiei o link:

http://mundoprojetado.com.br/wp-content/uploads/2018/06/Template2-e1528172108632.png

Caso você queira usar uma imagem que você criou e não existe online, é só utilizar algum site de hospedagem de imagens. Depois de fazer o upload da imagem para o site, é só copiar o link, que funcionará da mesma forma.

Obs: O link tem que terminar com o formato do arquivo (.png ou .jpg).

Agora, resta apenas enviar o elemento HTML “img” com o comando client:send.

client:send(“<img src=’COLOQUE-O-LINK-AQUI’>”)

E o resultado final pode ser visto abaixo:

NodeMcu Web server com imagem

Utilizando um arquivo .html

Escrever e enviar separadamente cada linha do seu web server pode ser uma tarefa complicada. Principalmente para organizar e entender melhor o seu código. Portanto, é possível carregar a sua página a partir de um arquivo html dentro do NodeMcu.

O primeiro passo é fazer o upload do seu arquivo. Para isso, clique no botão upload no canto inferior esquerdo do ESPlorer e selecione seu arquivo. Uma dica: não deixe linhas vazias no seu código, pois pode dar problema. Feito isso, basta utilizar o seguinte código:

Código

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
wifi.setmode(wifi.STATION)
wifi.sta.config({ssid="NOME_DO_SEU_WI-FI", pwd="SENHA_DO_WI-FI"})

tmr.alarm(0, 1000, 1, function() --Aguarda o esp conectar na rede
   if wifi.sta.getip() == nil then
      print("Conectando à rede...\n")
   else
      ip=wifi.sta.getip()
      print("IP: ",ip)
      tmr.stop(0)
   end
end)


srv = net.createServer(net.TCP)

srv:listen(80,function(conn)
    conn:on("receive", function(client, payload)

        local _line       --Variavel para leitura das linhas
        if file.open("index.html","r") then --Se abrir o arquivo corretamente
        repeat
            _line = file.readline() --Lê a linha
            if (_line~=nil) then  --Se não for nula, envia os dados
               client:send(string.sub(_line,1,-2))  --ignora o pulador de linha
            end
        until _line==nil --Repete até a ultima linha do arquivo
        file.close() --Termina a leitura do arquivo
        end
       
        client:on("sent", function(conn) conn:close() end)
    end)
end)

Obs: ou você nomeia o seu arquivo .html para “index” ou muda a linha do ‘if file.open’ para o nome do seu arquivo.

A maior parte do código você já viu nos tópicos anteriores. A única diferença está na parte de enviar os dados da página para o cliente – client:send(). A diferença aqui é que toda a parte do envio está envolvida em uma repetição que lê o arquivo, verifica se a linha é válida e então envia a linha que foi lida. Recomendo ler os comentários para entender melhor.

Com isso, seu código fica bem mais organizado, pois o HTML fica separado em um arquivo totalmente diferente. Assim, fica mais fácil identificar erros e mais tranquilo de entender e desenvolver seu código.

Vale lembrar que, se for utilizar acentos ou caracteres especiais, você deve acrescentar o elemento meta abaixo:

<meta http-equiv=”Content-Type” content=”text/html; charset=utf-8″>

 

Agora você já pode criar seu próprio web server com informações e textos bem interessantes. Na próxima aula, veremos como colocar botões para comandar LEDs a distância e como exibir dados de um sensor.

Enviar e receber dados pelo Web Server do NodeMcu – Aula 7 – NB