ESP32

Como usar socket com ESP32

Seja o protocolo que for, por mais simples que seja, nada vai ser tão leve quanto abrir uma comunicação via socket. Se for UDP, mais leve ainda, pois o UDP não tem compromisso com a entrega dos pacotes, não verifica se foi entregue e também não entrega ordenadamente. O TCP inclui algumas entradas no header e tem todos os ítens supracitados. Mas ainda assim, nada é mais leve. Já o controle fica por conta do programador, mas ainda assim é uma boa experiência. Vamos ver como utilizar socket com ESP32?

Artigos relacionados

Já escrevi alguns artigos de comunicação por socket. O legal de utilizar socket é que fica fácil testar com qualquer coisa. Um simples comando telnet já pode acionar um relé, por exemplo.


Se desejar ver uma comunicação socket com Qt (que é um framework de C++, e minha paixão), tem esse artigo. Socket era bastante utilizado para comunicação local, mas com a chegada dos IPCs, os recursos primários do UNIX foram ficando para trás – e não estou dizendo que outras plataformas não tenham sockets. É que o UNIX tem um outro tipo de socket, justamente para fazer IPC; o UNIX sockets. Ele não utiliza a camada de rede, é bem interessante. Se quiser ver a respeito, escrevi esse artigo.

Socket com ESP32

Eu não encontrei na documentação oficial nenhuma referência à comunicação via socket. Passei 2 dias fazendo testes, até encontrar um exemplo de socket no ESP32 em um repositório no github. Eu já havia tentado de todas as formas imagináveis, iniciei o projeto no CodeBlocks várias e várias vezes, escrevendo linha por linha. No final, o exemplo era para utilizar diretamente no ESP-IDF, todo escrito em C. Implementei devagar até conseguir fazer funcionar, portanto, sugiro que guarde com carinho essa dica porque não foi fácil nem é simples.

Algumas funções eu já tinha implementado; a conexão WiFi também fiz de um jeito diferente, invés de usar a biblioteca WiFi do Arduino. A task que controla o socket eu coloquei no núcleo 0 para evitar qualquer problema com o loop no núcleo 1 (porque se o socket ficar preso tempo demais, pode interferir inclusive na própria conexão WiFi e daí começa o espetáculo de “insetos”).

Socket server em Python

No Linux eu fiz um socket server em Python. Porque? Bem, todos os testes iniciais foram focados em criar um socket server, mas nada funcionou. Tive erros relacionados à compilação da API do Arduino para o ESP, pra ter uma ideia. Daí achei melhor (mais fácil) implementar um client, já que o server pode responder à requisição. Então o client manda uma mensagem qualquer (coloquei sendMeCommand pra ficar bonitinho) e o server responde com um comando, que pode ser passado pelo usuário de diversas maneiras. Vou fazer de um jeito pouco usual porque estou extremamente desgastado e nem publiquei outro artigo porque dediquei todo meu tempo livre a resolver essa problemática; ficaria muito frustrado se não conseguisse resolver essa questão, afinal, a coisa mais básica em qualquer linguagem ou sistema é abrir um socket.

Placa de desenvolvimento para ESP32

Para escrever esse artigo, utilizei a placa de desenvolvimento da imagem de destaque (e também do video), vendida na CurtoCircuito (clique para vê-la no site). Vou dar minha opinião sobre ela.

Para profissionais

Bem, se você tiver um produto com ESP32 e a gravação for por FTDI, é a pior das situações; desconectar e conectar DTR, TX, RX, VCC e GND não é lá uma tarefa muito divertida. Agora, fazer isso para, digamos, 50 placas, tem que ter muita paciência. Com uma placa de desenvolvimento você poderá apenas ir trocando os processadores e gravando. Além do mais, ele tem um botão de liga/desliga que dispensa a necessidade de desconectar o cabo toda a vez que for trocar de processador.

Para hobistas

Ótimo para colecionar ESP32. Eu quis muito essa board porque assim posso adquirir diversos módulos e gravar programas específicos em cada um deles. Depois é só colocar de novo na board e brincar com o respectivo programa, bastando rotular o processador para saber sua função. Além do mais, fica fácil de armazenar um monte de ESP32, porque ele é pequeno fora de um circuito. E não tem que não goste dessa placa, causa uma ótima impressão; com alguns módulos o investimento já retornou.

Módulo relé

Para fazer essa comunicação e testá-la, a primeira coisa que pensei foi em bater um relé. Convenhamos, é o mesmo processo de acender um LED, mas é mais legal ouvir os “plecs” do que acender um LED.


Conectei o módulo em 3V3 porque os pinos do ESP não são tolerantes a 5V. Consegui drivar sem problemas. Também, o módulo tem lógica invertida, que acende quando aterrado no pino do processador, e é bem melhor assim no meu caso porque o módulo não é opto-acoplado e ao contrário poderia consumir corrente demais do pino de GPIO.

Esse módulo relé é comum, nada de especial, exceto pelo fato de que é vendido na AutocoreRobotica. Agora tem diversos modelos, e o desse link é opto-acoplado, que garante um isolamento do circuto e é acionado com baixíssima corrente, por isso recomendo.

Pinout do ESP32

Como estamos tratando diretamente com o módulo castellated (esse é o nome do acabamento na borda do módulo com o processador; presume-se o porquê), precisamos ter uma referência sobre os recursos dos GPIO. Eis:

Socket com ESP32
Socket com ESP32 – ESP32 Pinout

Na placa de desenvolvimento estão dispostos os pinos de GPIO. Eu optei por usar o 26 e o 27 para os acionadores dos relés.

Criação do projeto

Para criar esse projeto, utilizei o CodeBlocks com PlatformIO. Já mostrei nesse artigo como utilizar o CodeBlocks  para programar Arduino, mas agora vou explicar um pouco mais sobre os comandos para O PlatformIO.

Instalação da board

Quando criamos um projeto com uma board que a configuração de hardware e toolchain não estão disponíveis, o download é feito automaticamente. Isso é ótimo, pois não precisamos nos preocupar com o risco de esquecer alguma coisa e o projeto não funcionar.

Para criar esse projeto, o procedimento é o seguinte:

E aí é só contemplar o processo. Para ver as opções utilizando ESP32, fiz uma pesquisa na base de placas do PlatformIO, dessa maneira:

Vou dar uma sugestão que pode parecer meio boba, mas pode evitar problemas. Sempre que for utilizar o programa platformio, esteja primeiramente dentro do diretório do respectivo projeto.

Instalação de bibliotecas

É fácil instalar uma biblioteca por linha de comando. Podemos pesquisar previamente com o comando platformio lib search <lib>:

Socket com ESP32

Existem diversos comandos de manipulação de biblioteca, mas não se preocupe em decorar nda, simplesmente digite platformio lib para ver as opções relacionadas. Se esquecer os parâmetros que procedem ao platformio, digite apenas platformio para ver as opções. Não tem segredo.

Só para deixar claro, o comando platformio lib search procura no repositório oficial do Arduino, não é local.

Código

Como citei mais acima, procurei o caminho mais fácil. Coloquei dentro do socket server uma chamada; cada vez que ele recebe uma mensagem, verifica em /dev/shm (que é um sistema de arquivos na memória, utilizando o ramfs) se tem um arquivo chamado command. Se tiver, ele abre o arquivo, lê o comando, fecha e remove o arquivo. Se não, envia  simplesmente “-“.

Os comandos implementados foram:

  • 0 – para desligar ambos os relés
  • 1 –  para acionar ambos os relés
  • 2 – para acionar o relé 1
  • 3 – para acionar o relé 2

Isso já é o suficiente para a prova de conceito.

Quando o server está fora, não há danos ao socket client, ele simplesmente imprime uma mensagem relacionada à indisponibilidade da conexão, mas assim que o server estiver funcionando, a comunicação inicia (ou reinicia). Já do lado server, fica sempre escutando, mas se interrompido, o socket permanece um tempo indisponível até que o sistema nativo remova ele pelo timeout do socket, conforme os padrões configurados nativamente no sistema. Dá pra reduzir o timeout do socket pelo sysctl, mas o foco desse artigo não é Linux, por isso vou deixar para outra ocasião.

Socket server

Peguei um código prontinho de exemplo na própria documentação do Python, assim economizei tempo escrevendo esse código. Só modifiquei alguns parâmetros e adicionei as funcionalidades relacionadas à interação com com o sistema de arquivos. O código ficou assim:

Para executar, basta chamar na linha de comando:

Chamei o script Python de boss.py, já que é ele quem manda.

Socket client

Esse, rodando no ESP32, deu um trabalho monstro, porque apesar de (após 2 dias) ter encontrado o código que servia, ainda tive que fazer alguns ajustes. Criei a função de controle dos relés fora da task, depois chamei a função na sequência da leitura de resposta.

Eu sei que o código vai assustar um pouco quem está acostumado com Arduino, mas antes de por o código completo, vou dissecar as funções para deixar claro o que fiz. Só os includes que são assustadores mesmo, mas se esquecer de colocar um que dependa do outro, é problema na certa.

Cabeçalhos

Os cabeçalhos são as bibliotecas que contém suas respectivas funcionalidades. Elas estão em lugares diferentes, conforme sua categora. Isso deu um bocado de trabalho também, porque além de não saber quais eram as dependências fazendo às escuras, algumas bibliotecas eu não tinha. E o CodeBlocks eu acho que poderia se chamar “CodeBugs”, pois travou diversas vezes durante esses 2 dias de pesquisas e testes. Vou escrever um artigo com uma IDE muito melhor logo mais.

Defines

Logo após os includes tem alguns defines para constantes utilizadas no código:

Qualquer porta acima de 1024 é elegível, eu preferi utilizar 8888.

Defini uma constante de um buffer, mas pelo que estou vendo nem utilizei na última implementação.

DEFAULT_SSID e DEFAULT_PWD são redefinições, coloque suas credenciais para conectar o ESP32 à sua rede WiFi.

TCPSERVER é o endereço IP ou URL onde executará o script Python socket server.

MESSAGE é um mero gatilho pra buscar status no tcp server.

Manipulador de eventos

Uma função foi definida para tratar eventos do sistema. Ela retorna uma definição de tipo uint32_t, mas eu sequer me preocupei em guardar o retorno.

Conexão WiFi

Essa eu fiquei bastante feliz em fazer sem usar o “modo Arduino”. Não se preocupe com a estrutura. Se quiser utilizar os recursos como estou fazendo, sugiro que guarde templates separados com cada funcionalidade para consulta posterior ou faça um bookmark do artigo.

UART (Serial)

Nesse outro artigo mostrei detalhes de como utilizar a UART do ESP32 sem precisar do recurso Serial do Arduino. Aqui só estou reimplementando:

Depois tem mais 3 linhas na função setup(), como pode ser visto mais abaixo.

Task da comunicação TCP

Em uma das primeiras implementações de socket que tentei fazer no ESP32 não utilizei task, mas foi claramente um erro. Para ter uma ideia da gravidade, executei todo o código no núcleo 1, que é justamente onde roda a função loop da API do Arduino. Quando o socket entrava, causava um reset por WDT. Espero que esteja se acostumando a criar threads em seus programas com ESP32.

setup()

A função setup() fica linda, não tem quase nada e é feita só por chamadas. As primeiras 4 linhas são relacionadas à configuração dos pinos de GPIO, seguido por 3 linhas de configuração da UART. Depois inicializamos a conexão com nossa rede WiFi e por fim, criamos a task.

loop()

Nadinha. Nadinha de nada; necas de pitibiriba; coisa nenhuma. Todos os serviços relacionados estão sendo executados em threads. A comunicação WiFi e UART estão rodando no núcleo 1. Isso porque setup()loop() rodam no núcleo 1 e tudo o que for chamado dentro deles, roda no mesmo núcleo. A excessão é a criação de tasks com especificação do núcleo a rodar.

Código completo do socket client

O código completo ficou assim:

Agora, apesar de ser um monte de linhas, as funções são simples, certo?

Script shell para interagir com os GPIO

O socket server é um serviço. Ele não precisa (e certamente não deveria) fazer outra coisa que não o gerenciamento da conexão. Para acionar os relés, escrevi um programa à parte, bem simples, utilizando um menu em ncurses, De modo que ninguém precisa saber o comando que será enviado, fica uma interface de, digamos “alto nível” com o usuário.

Uma dependência é o programa dialog. Para instalar tudo adequadamente, leia esse artigo.

Colocado em loop infinito até que seja interrompido pelo botão Cancel, o script fará a interação necessária para o acionamento dos relés.

Socket com ESP32 - script shell
script shell – Socket com ESP32

Quando selecionada uma opção, existe um delay na comunicação, então para não ficar parado em uma tela estática, coloquei um timer de 5 segundos decrementando o tempo para ter um informativo.

Socket com ESP32

Programa gráfico para interagir com o GPIO

Fiz o programa gráfico em meu framework preferido de C++, o Qt. O programa é ridículamente simples.

O código desse programa está disponível no meu repositório do github. A janela é bem simples:

Programa em Qt - Socket com ESP32
Programa em Qt -Socket com ESP32

Fiz tudo na QMainWindow, não tem nada de especial.

mainwindow.cpp

E o header, dessa classe, o mainwindow.h

O desenho da janela foi feito no mainwindow.ui, mas não faz sentido dispor o código aqui.

No arquivo .pro do projeto, adicione o suporte a rede. A respectiva linha deve ficar assim:

Baixando o projeto do github, bastará abrir e compilar.

IDEs utilizadas para programar

Para programar em Python, utilizei o PyCharm. Ele é gratuito e vem com as funcionalidades pagas durante 30 dias, se não me engano. Mas provavelmente você não sentirá falta dos recursos da versão paga.

Para programar o ESP32, utilizei o CodeBlocks. Para instalar ele e suas dependências, sugiro a leitura desse artigo.

Para programar o shell script eu utilizei o vim, mas se não tiver habilidades com o vim, você sequer conseguirá sair do modo de edição do arquivo, então recomendo que utilize o Atom.

Para programar em Qt, utilizei o QtCreator. Você pode instalá-lo pelo gerenciador de pacotes do Linux ou baixar o instalador para outras plataformas no site do Qt.

Video

O video é simples, mas mostro um pouco de cada programa, explico o payload da comunicação e você pode ver tudo isso rodando.

Siga-nos no Do bit Ao Byte no Facebook.

Prefere twitter? @DobitAoByte.

Inscreva-se no nosso canal Do bit Ao Byte Brasil no YouTube.

Nossos grupos:

Arduino BR – https://www.facebook.com/groups/microcontroladorarduinobr/
Raspberry Pi BR – https://www.facebook.com/groups/raspberrybr/
Orange Pi BR – https://www.facebook.com/groups/OrangePiBR/
Odroid BR – https://www.facebook.com/groups/odroidBR/
Sistemas Embarcados BR – https://www.facebook.com/groups/SistemasEmbarcadosBR/
MIPS BR – https://www.facebook.com/groups/MIPSBR/
Do Bit ao Byte – https://www.facebook.com/groups/dobitaobyte/

Próximo post a caminho!