Introdução
Neste artigo, vamos explorar a conexão WiFi da Franzininho WiFi Lab01 para criar o nosso próprio Web Server. O objetivo é entender como funciona a comunicação entre cliente e servidor, para possibilitar o desenvolvimento de um servidor web capaz de controlar o estado do LED na placa, permitindo ativar e desativar.
O que é a Comunicação Cliente-servidor?
A estrutura cliente-servidor implica na comunicação entre dois programas distintos: o cliente, responsável por enviar solicitações, e o servidor, encarregado de responder a essas solicitações. Abaixo, temos um esquema que ilustra essa organização.
Primeiramente, é essencial compreender o papel crucial dos sockets na implementação desse sistema. Os sockets são mecanismos de comunicação que permitem a troca de dados entre processos distintos.
Assim, o servidor cria um socket para estabelecer a conexão e aguarda conexões de clientes. Enquanto o cliente cria um socket e se conecta ao socket do servidor utilizando o endereço IP e a porta específicos do servidor. Como tanto o cliente quanto o servidor têm seus próprios sockets, a comunicação entre eles é bidirecional.
Nesse contexto, temos o método bind, utilizado para vincular o socket do servidor a uma interface de rede específica e a uma porta designada para aguardar conexões. Já no caso do cliente, esse procedimento geralmente não é necessário.
O listen é utilizado para colocar o socket do servidor em um estado de escuta, permitindo que ele aguarde por conexões de clientes.
Do lado do servidor temos o accept utilizado para aceitar uma conexão de um cliente quando ela ocorre. Já no lado do cliente temos o método connect utilizado em um socket para iniciar uma conexão com um servidor. Quando uma conexão é estabelecida, o accept retorna um novo socket que representa a conexão com o cliente e o endereço do cliente.
Por fim, os métodos send e recv são utilizados para enviar e receber dados através de sockets.
Recursos necessários
Para iniciar o trabalho com os GPIOs, é essencial possuir o diagrama de pinos da placa à disposição, pois isso vai permitir que você identifique tanto os nomes quanto as funções associadas a cada um deles.
| Pino | Recurso |
| IO1 | LDR |
| IO2 | BT6 |
| IO3 | BT5 |
| IO4 | BT4 |
| IO5 | BT3 |
| IO6 | BT2 |
| IO7 | BT1 |
| IO8 | OLED_SDA |
| IO9 | OLED_SCL |
| IO10 | TFT_DC |
| IO11 | TFT_RES |
| IO12 | LED AZUL |
| IO13 | LED VERDE |
| IO14 | LED VERMELHO |
| IO15 | DHT11 |
| IO17 | BUZZER |
| IO35 | TFT_SDA |
| IO36 | TFT_SCL |
Código Web Server em MicroPython
Para criar um Web Server é preciso criar dois arquivos: boot e main.
Boot
Com a Franzininho WiFi Lab01 conectada ao seu computador, abra o Thonny e crie um novo arquivo contendo o código do boot:
import socket, network
from machine import Pin
import esp, gc
# gerenciador de memória
esp.osdebug(None)
gc.collect()
# dados da rede
ssid = 'SUBSTITUA_PELO_SEU_SSID'
password = 'SUBSTITUA_PELA_SUA_SENHA'
# configurando como cliente
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
# verifica conexão
if wlan.isconnected() == False:
wlan.connect(ssid, password)
# espere conectar
while wlan.isconnected() == False:
pass
print('connected!')
print(wlan.ifconfig())
led = Pin(13, Pin.OUT)Como mencionado anteriormente, criamos um servidor web usando sockets e a API de sockets do Micropython. Além de importar a biblioteca de sockets, é necessário importar a biblioteca de rede – network. Ela nos permite conectar o ESP32, microcontrolador da Franzininho Wifi Lab01, a uma rede Wi-Fi.
É preciso, também, importar a classe Pin de ‘machine’ para interagir com os GPIOs da Franzininho:
import socket, network
from machine import Pin
import esp, gcAs duas últimas bibliotecas são importadas no intuito de realizar uma economia de recursos. A biblioteca ‘esp’ é importada para desativar as mensagens de depuração do sistema operacional, utilizando a função ‘osdebug’. Já a biblioteca ‘gc’, de garbage collector ou coletor de lixo, é uma maneira de recuperar a memória ocupada por objetos que não estão mais em uso pelo programa. Isso será útil para economizar espaço na memória flash:
esp.osdebug(None)
gc.collect()Em seguida, são definidas duas variáveis: ssid e password que são responsáveis por guardar o SSID e a senha da sua rede, respectivamente, para que o ESP possa se conectar ao seu roteador:
ssid = 'SUBSTITUA_PELO_SEU_SSID'
password = 'substitua_pela_senha'Lembre-se de alterar essas variáveis para conexão ocorrer corretamente.
Em seguida, vamos configurar o ESP32 para se conectar a uma rede Wi-Fi como cliente. Primeiro um objeto ‘WLAN’ é criado usando a classe ‘STA_IF’ de ‘network’. O ‘WLAN’ representa a interface sem fio do microcontrolador e ‘STA_IF’ indica que estamos configurando a interface como uma estação Wi-Fi – conhecido como cliente:
wlan = network.WLAN(network.STA_IF)A configuração seguinte ativa a estação Wi-Fi no microcontrolador, permitindo que ele procure e se conecte a redes Wi-Fi disponíveis. ‘True’ indica que a estação Wi-Fi deve ser ativada:
wlan.active(True)Após executar esses comandos, o microcontrolador ESP32 está pronto para se conectar a uma rede Wi-Fi como cliente.
Para realizar a conexão, iniciamos verificando se o dispositivo já está conectado à rede Wi-Fi com ‘wlan.isconnected()’. Se o dispositivo não estiver conectado, ele tenta se conectar usando o nome da rede (SSID) e a senha fornecidos anteriormente.
Há um loop que espera até que o dispositivo esteja totalmente conectado à rede. O loop é mantido enquanto ‘wlan.isconnected()’ retornar falso, indicando que o dispositivo ainda não está conectado. O ‘pass’ significa que o loop não fará nada enquanto aguarda a conexão:
if wlan.isconnected() == False:
wlan.connect(ssid, password)
while wlan.isconnected() == False:
passSe a conexão ocorrer será exibido no terminal “connected!”. Em seguida, utilizando ‘ifconfig()’ de ‘WLAN’, serão impressas informações da configuração da interface de rede, como endereço IP, máscara de sub-rede, gateway, etc.
O servidor web será acessado em um navegador web utilizando o endereço IP fornecido pelo ‘ifconfig()’.
Por último, selecionamos o GPIO 13, que está associado ao LED verde e será o LED aceso na interface do servidor web.
Main
O main conterá o script que permitirá a construção da página web. Assim, começamos criando uma função chamada ‘web_page()’. Esta função retorna uma variável chamada ‘html‘, que contém o código HTML necessário para criar a página da web:
def web_page():
if led.value() == 1:
gpio_state="ON"
else:
gpio_state="OFF"
html = """<html><head> <title>My Web Server</title> <meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" href="data:,"> <style>html{font-family: Helvetica; display:inline-block; margin: 0px auto; text-align: center;}
h1{color: #0F3376; padding: 2vh;}p{font-size: 1.5rem;}.button{display: inline-block; background-color: #e7bd3b; border: none;
border-radius: 4px; color: white; padding: 16px 40px; text-decoration: none; font-size: 30px; margin: 2px; cursor: pointer;}
.button2{background-color: #4286f4;}</style></head><body> <h1>Franzininho Web Server</h1>
<p>LED status: <strong>""" + gpio_state + """</strong></p><p><a href="/?led=on"><button class="button">ON</button></a></p>
<p><a href="/?led=off"><button class="button button2">OFF</button></a></p></body></html>"""
return html
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('', 80))
s.listen(5)
while True:
conn, addr = s.accept()
print('Got a connection from %s' % str(addr))
request = conn.recv(1024)
request = str(request)
print('Content = %s' % request)
led_on = request.find('/?led=on')
led_off = request.find('/?led=off')
if led_on == 6:
print('LED ON')
led.value(1)
if led_off == 6:
print('LED OFF')
led.value(0)
response = web_page()
conn.send('HTTP/1.1 200 OK\n')
conn.send('Content-Type: text/html\n')
conn.send('Connection: close\n\n')
conn.sendall(response)
conn.close()A página da web irá mostrar o estado atual do GPIO, indicando se o LED está ou não ativado. Então, antes de gerar o texto HTML, precisamos verificar o estado do LED. O estado é salvo na variável ‘gpio_state’:
if led.value() == 1:
gpio_state="ON"
else:
gpio_state="OFF"Essa variável é incorporada ao texto HTML usando os sinais de “+” para concatenar strings. O texto em HTML cria uma página simples que exibe o texto “Franzininho Web Server”, o estado atual do LED e fornece dois botões para ligar e desligar o LED:
html = """<html><head> <title>My Web Server</title> <meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" href="data:,"> <style>html{font-family: Helvetica; display:inline-block; margin: 0px auto; text-align: center;}
h1{color: #0F3376; padding: 2vh;}p{font-size: 1.5rem;}.button{display: inline-block; background-color: #e7bd3b; border: none;
border-radius: 4px; color: white; padding: 16px 40px; text-decoration: none; font-size: 30px; margin: 2px; cursor: pointer;}
.button2{background-color: #4286f4;}</style></head><body> <h1>Franzininho Web Server</h1>
<p>LED status: <strong>""" + gpio_state + """</strong></p><p><a href="/?led=on"><button class="button">ON</button></a></p>
<p><a href="/?led=off"><button class="button button2">OFF</button></a></p></body></html>"""
return htmlA página web será conforme mostrado na figura abaixo:
Definida a página web, é criado um servidor básico usando sockets no Python para responder às solicitações HTTP. Vamos entender o que está acontecendo em cada parte.
Primeiro, um socket é criado usando a família de endereços ‘AF_INET’, o qual indica que o protocolo de comunicação será o IPv4 (Internet Protocol version 4). Já o tipo de socket é definido como ‘SOCK_STREAM’ que é utilizado para conexões TCP. O socket é vinculado ao endereço IP vazio (”) e à porta 80. O método ‘listen(5)’ especifica o número máximo de conexões pendentes que o socket poderá ter:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('', 80))
s.listen(5)No loop, ao receber uma conexão, a função ‘accept()‘ retorna um novo socket denominado ‘conn‘ e o endereço do cliente é armazenado na variável ‘addr‘. Feito isso, o ‘request’ recebe a solicitação HTTP do cliente e a solicitação é convertida para uma string:
conn, addr = s.accept()
request = conn.recv(1024)
request = str(request)Após isso, é verificado se a solicitação contém ‘/?led=on‘ ou ‘/?led=off‘, que são os comandos para ligar ou desligar o LED. Se uma correspondência for encontrada, o estado do LED é alterado usando ‘led.value()‘. Em seguida, a função ‘web_page()‘ é chamada para gerar o conteúdo HTML da resposta:
led_on = request.find('/?led=on')
led_off = request.find('/?led=off')
if led_on == 6:
led.value(1)
if led_off == 6:
led.value(0)response = web_page()Por último, enviamos a resposta do servidor de volta ao cliente após receber a solicitação HTTP. O comando ‘conn.send('HTTP/1.1 200 OK\n')’ envia a linha de status HTTP ao cliente, indicando que a solicitação foi bem-sucedida. Já ‘conn.send('Content-Type: text/html\n')’ é para informar que o tipo de conteúdo enviado é HTML.
O comando ‘conn.send('Connection: close\n\n')’ informa que a conexão TCP será fechada após a conclusão da resposta. E o comando ‘conn.sendall(response)’ envia o conteúdo gerado pela função web_page() (a página HTML criada anteriormente) para o cliente.
Finalmente, ‘conn.close()’ indica que a conexão com o cliente é fechada, liberando os recursos associados à conexão:
conn.send('HTTP/1.1 200 OK\n')
conn.send('Content-Type: text/html\n')
conn.send('Connection: close\n\n')
conn.sendall(response)conn.close()Abaixo temos o resultado do servidor web, lembrando que para alterar o estado do led basta pressionar os botões do servidor:
Conclusão
Neste artigo, exploramos de maneira abrangente o desenvolvimento de um servidor web utilizando a placa Franzininho Wifi Lab01. Desde os estágios iniciais de estabelecimento da conexão até a criação da página HTML.
Além disso, discutimos o papel significativo dos métodos ‘bind’, ‘listen’, ‘accept’, ‘connect’, ‘send’ e ‘recv’ na estrutura cliente-servidor, ressaltando suas respectivas funções na criação e gerenciamento de conexões.
Em resumo, tivemos uma introdução prática sobre a criação de um servidor web utilizando a Franzininho Wifi Lab01. Como sugestão para explorações futuras, recomenda-se a personalização da interface do servidor web, como também a exploração de possibilidades que permitam ao servidor ter mais funções para o controle dos recursos na placa.






