ESP8266-201: Medindo sinal do WiFi usando Socket


Neste artigo vamos falar sobre o ESP8266-201. Sei que pouca gente conhece essa versão, mas eu gosto bastante por conta de sua possibilidade de conexão de antena. Fizemos, então, uma montagem para medir a intensidade de sinal de WiFi. Para isso, tornamos o ESP201 um Access Point. Comunicamos remotamente um segundo ESP8266-201 client com servidor e medimos a força de sinal entre eles (dbm).
Pegamos, portanto, dois ESP201 que possuem conector PigTail e ligamos a uma antena. Fizemos um programa usando Socket TCP que envia um pacote e recebe a potência em dbm (decibel miliwatt). Isso é bastante útil, por exemplo, quando você está automatizando sua residência e não sabe se o ESP utilizado vai chegar até o ponto de distância pretendido. Com a montagem de hoje será possível descobrir isso na prática. Você ainda pode usar esse mesmo exemplo com o ESP01.
A utilização da comunicação Socket também será abordada hoje, a qual possui o Station e o Client.

 Recursos usados

  2 ESP 8266-201;
  2 Displays Oled;
  2 Antenas para módulo WiFi do ESP 2,4G;
  2 botões;
  2 porta pilhas;
  4 pilhas 8800mA;
  Jumpers.


ESP8266-201 Pinout

Aqui temos o Pinout do ESP201 que não é tão comum, mas fácil de ser encontrado na internet. Além do conector PigTail, ele tem mais IO.

Ligação de pinos

Aqui temos o esquema da montagem, o qual basta seguir, pois está bem simples.

Distância medida

Neste mapa marquei o ponto 0 e sai caminhando em linha reta  para identificar a distância alcançada entre os dois ESPs. Chegamos a aproximadamente 120 metros entre as duas antenas. Em um primeiro teste que fizemos, no ano passado, chegamos a alcançar 242 metros. No entanto, nesta nova tentativa chegamos a somente 120m. O motivo desta mudança? Não sei, mas tenho uma teoria. Acho que o ar aqui onde fazemos os teste está mais sujo, com muita conexão WiFi, o que deve estar atrapalhando. Mas, claro que pode ser outra coisa que desconheço já que o WiFi é um terreno movediço. A minha dica aqui é que vocês usem antena externa, pois faz muita diferença e você vai bem mais longe.
O menor sinal que identificamos é o -96dbm. Se chegar a -97dbm, então, cai a comunicação. Esse número identificamos na prática, muito melhor que em contas.

Circuito

Na nossa montagem nós temos o AP, que funciona como servidor, e o Station, que é o Client. O client envia os dados ao server, que são exibidos nos displays de ambos. Nas duas partes, os ESP201 estão ligados em antenas. No lado traseiro nós instalamos duas baterias de lítio em cada parte. Quanto mais paralelas as antenas estiverem melhor será a propagação do sinal. Por fim, no Client um led pisca a cada envio de pacote ao AP.

Código Servidor (Access Point)

Código Server - Includes e configurações
Aqui tratamos do código do server e, o que o server faz? Primeira coisa: ele é o AP, ou seja, o acesso. Ele inicia como Access Point e fica esperando o cliente conectar nele. Ele fica em listen e quando ele chegar uma string ele vai e imprime na tela do display Oled. 
Nesta parte do código incluímos as libs, criamos o objeto, definimos o IP local, porta, subnet e criamos ainda o WiFiserver, que tem número do porte do Socket marcado em 5000.

#include <ESP8266WiFi.h> //lib para conectar o wifi do ESP201
#include <U8x8lib.h> //lib usada para comunicação com o display
#include <SPI.h> //protocolo síncrono de dados serial

//SCL (ou serial clock) indica o sinal do clock, que é enviado do servidor para todos os clientes. Todos os sinais SPI são síncronos com este sinal
//SDA (ou serial data) é o pino que efetivamente transfere os dados
//O 3º parameto deve ser um inteiro, ele nada mais é do que o pino do reset. 'U8X8_PIN_NONE' é usado por que este pino não está conectado
U8X8_SSD1306_128X32_UNIVISION_SW_I2C u8x8(SCL, SDA, U8X8_PIN_NONE); 

//ip da rede local
IPAddress local_IP(192, 168, 10, 11);
//gateway da rede local
IPAddress gateway(192, 168, 10, 10);
//subnet é uma divisão lógica da rede local
IPAddress subnet(255, 255, 255, 0);

//define servidor na porta 5000 do protocolo TCP
WiFiServer servidor(5000);

Código Server - Setup
Aqui configuramos o pino do led, inicializamos o display, configuramos a fonte de texto e fazemos uma função para escrever no display. Configuramos ainda o modo como Access Point.

void setup()
{
  //seta o pino do led
  pinMode(13, OUTPUT);
  //inicializa display
  u8x8.begin();
  //desativa o modo de economia de energia do display
  u8x8.setPowerSave(0);
  //configura a fonte do texto que será exibido
  u8x8.setFont(u8x8_font_chroma48medium8_r);

  //aguarda 5 segundos
  delay(5000);

  //escreve no display "Definindo modo"
  escreva("Definindo modo", true, 1000, false);
  
  //configura modo como access point
  WiFi.mode(WIFI_AP);
  
  //escreve no display "Pronto"
  escreva("Pronto!", false, 1000, true);

Na sequência, determinamos que, enquanto a interface de rede do Access Point não for configurada será exibido um ponto, ou seja, “.”. Também definimos o que será escrito no display para outras situações e os parâmetros da rede, como nome e senha, sendo que WiFi_Range é o nome da rede que o Client vai conectar.

  

//escreve no display "Definindo AP"
escreva("Definindo AP", true, 1000, false);
  //enquanto a interface de rede do access point não for configurada, exibe "."
  while (!(WiFi.softAPConfig(local_IP, gateway, subnet))) 
    escreva(".", false, 100, false);  
  
  //escreve no display "Definindo AP"
  escreva("Pronto!", false, 1000, true);

  //escreve no display "Definindo rede"
  escreva("Definindo rede", true, 1000, false);

  //enquanto a rede não for definida, escreve "."
  //parametros: WiFi.softAP(nomeDoAccessPoint, senhaRede, canal, redeVisivel)
  //canal: canal usado pelo ESP, pode ser do 1 ao 11
  //redeVisivel: a rede pode ou não aparecer para outros serviços 
  while (!(WiFi.softAP("WiFi_Range", "12341234", 6, false))) 
    escreva(".", false, 100, false);
  
  //escreve no display "Definindo AP"
  escreva("Pronto!", false, 1000, true);

Nesta parte tratamos no display do endereço de IP, entre outros. Inicializamos o servidor sem delay na comunicação TCP.

  
//escreve no display "Endereco IP"
escreva("Endereco IP", true, 1000, false);
  
  //escreve no display o ip do servidor
  escreva(WiFi.softAPIP().toString(), false, 1000, true);
  
  //escreve no display "Iniciando"
  escreva("Iniciando", true, 10, false);
  
  //escreve no display "servidor"
  escreva("servidor...", true, 1000, false);

  //inicializa servidor
  servidor.begin();

  //define servidor para trabalhar sem delay
  //caso seja setado como true, tem o intuito de reduzir o tráfego TCP / IP de pequenos pacotes 
  servidor.setNoDelay(true);
  
  //escreve no display "Pronto!"
  escreva("Pronto!", false, 1000, true);
  
  //escreve no display "Aguardando STA"
  escreva("Aguardando STA", true, 1000, false);
}


Código Server – Loop
O código trabalha nesta parte sobre a conexão entre servidor e Client. Instanciando o WiFiClient temos o objeto que vai guardar todas as propriedades do cliente.

void loop()
{
  //enquanto a quantidade de estações conectadas no servidor for zero
  //ou seja, ninguém conectou ainda
  while (WiFi.softAPgetStationNum() == 0)
  {
    //aguarda 1 segundo
    delay(1000);

    //se alguém conectou
    if (WiFi.softAPgetStationNum() != 0)
    {
      //exibe mensagem
      escreva("STA conectada!", true, 1000, false);
    }
  }

  //obtém o cliente que está conectado ao servidor
  WiFiClient client = servidor.available();


Em seguida configuramos suposições com o cliente e definimos uma string para exibição da força do sinal da estação. Limpamos o buffer de chegada, fechamos a conexão e apagamos o led.

if (client)
  {
    //limpa tela do display
    u8x8.clear();

    //acende o led
    digitalWrite(13, HIGH);

    //enquanto o cliente estiver conectado
    while (client.connected())
    {
      //se houver dados, leia
      if (client.available())
      { 
        //recebe dados do cliente
        String dbmSTA = client.readStringUntil('\n');
        
        //exibe a força do sinal da estação
        escreva("STA: " + dbmSTA, true, 1000, true);        
        
        //espera até que todos os caracteres de saída no buffer tenham sido enviados
        client.flush();
      }
    }
    //aguarda envio
    delay(1); 

    // fecha conexão
    client.stop();
    //apaga led
    digitalWrite(13, LOW);
  }
}



Código Server - Função “escreva”
Sobre a função “escreva”, tenho sempre a string que vou escrever no display. Nela também tratamos do intervalo e ainda tenho um comando para caso queira limpar a tela. Essa mesma função uso no cliente também.

//escreve no display de acordo com os parametros
//nl = pular linha
//intervalo = tempo enviado para o delay
//limpar = limpa a tela do display
void escreva(String texto, boolean nl, int intervalo, boolean limpar)
{
  //se deseja pular linha no display, então pula
  if (nl) 
    u8x8.println(texto);
  else  //se não, exibe texto sem pular linha
    u8x8.print(texto);

  //aguarda o intervalo passado por parametro
  delay(intervalo);

  //se deseja limpar o display, então limpa
  if (limpar) 
    u8x8.clear();
}

Código Cliente (Estação)

Código Client- Includes e configurações
Agora sobre o cliente temos as inclusões das libs, definições do display e criação de uma instância da classe ESP8266WiFiMulti. Também criamos uma instância da classe IPAddress e definimos o IP do servidor.

#include <ESP8266WiFi.h> //lib para conectar o wifi do ESP201
#include <ESP8266WiFiMulti.h>//lib para as funções addAP e  run
#include <U8x8lib.h>  //lib usada para comunicação com o display
#include <SPI.h>  //protocolo síncrono de dados serial

//SCL (ou serial clock) indica o sinal do clock, que é enviado do servidor para todos os clientes. Todos os sinais SPI são síncronos com este sinal
//SDA (ou serial data) é o pino que efetivamente transfere os dados
//O 3º parameto deve ser um inteiro, ele nada mais é do que o pino do reset. 'U8X8_PIN_NONE' é usado por que este pino não está conectado
U8X8_SSD1306_128X32_UNIVISION_SW_I2C u8x8(SCL, SDA, U8X8_PIN_NONE); 

//cria uma instância da classe ESP8266WiFiMulti
ESP8266WiFiMulti WiFiMulti;

//Criar uma instância da classe IPAddress e define o ip do servidor
IPAddress local_IP(192, 168, 10, 110);

Código Client – Setup
No Setup do cliente também definimos o pino do led, inicializamos o display e configuramos o modo como “Estação”.
void setup()
{
  //define pino Led
  pinMode(pinoLed,OUTPUT);
  
  //inicializa o display
  u8x8.begin();  
  
  //desativa o modo de economia de energia do display
  u8x8.setPowerSave(0);
  
  //configura a fonte do texto que será exibido
  u8x8.setFont(u8x8_font_chroma48medium8_r);
  
  //aguarda 1 segundo
  delay(1000);

  //escreve no display "Definindo modo"
  escreva("Definindo modo", true, 1000, false);
  
  //configura modo como estação
  WiFi.mode(WIFI_STA);

  //escreve no display "Pronto!"
  escreva("Pronto!", false, 1000, true);


Seguimos configurando parâmetros e também definimos nome da rede e senha, entre outros comandos.

//escreve no display "Definindo rede"
 escreva("Definindo rede", true, 1000, false);
  
  //parametros: WiFi.softAP(nomeDoAccessPoint, senhaRede)
  //redeVisivel: a rede pode ou não aparecer para outros serviços 
  WiFiMulti.addAP("WiFi_Range", "12341234");
  
  //escreve no display "Pronto!"
  escreva("Pronto!", false, 1000, true);

  //escreve no display "Conectando"
  escreva("Conectando...", true, 1000, false);

  //enquanto o cliente não estiver conectado, escreve "."
  while (WiFiMulti.run() != WL_CONNECTED) 
  escreva(".", false, 1000, false);

  //escreve no display "Pronto"
  escreva("Pronto!", false, 1000, true);

Prosseguindo com o Setup, definimos os textos a serem exibidos no display conforme cada situação.

  escreva("Endereco IP:", true, 1000, false);
    
  //escreve no display o ip local
  escreva(WiFi.localIP().toString(), false, 1000, true);
  
  //escreve no display "Conectando"
  escreva("Conectando",true,10,false);
  
  //escreve no display "com servidor..."
  escreva("com servidor...",true,10,false);
}

Código Client - Loop
No Loop o porte é definido como 5000. O IP deve ser o mesmo utilizado pelo servidor. Defino um cliente e conecto no “host port”. Se não fizer isso vai dar erro.

void loop() 
{
  //porta 5000 do protocolo TCP, deve ser a mesma utilizada pelo servidor
  const uint16_t port = 5000;
  //endereço ip, deve ser o mesmo utilizado pelo servidor
  const char * host = "192.168.10.11";

  //inicializa a lib do cliente
  WiFiClient client;

  //se o cliente não estiver conectado, exibe "Falha..."
  if (!client.connect(host, port)) 
  {
    escreva("Falha...",true, 1000,true);
    return;
  }


Pego a força do sinal da conexão entre os ESPs e jogo na string WiFi.RSSI. Acendemos o led, transmitimos a medida em dBm e exibimos a força do sinal da estação no display do server.

//obtém a força do sinal da conexão entre os ESPs
  String _RSSI = String(WiFi.RSSI());  
  
  //acende led
  digitalWrite(pinoLed,HIGH);
  
  //transmite esta medida em dBm
  client.println(_RSSI +"dBm");  
  
  //exibe a força do sinal da estação
  escreva("STA: " + _RSSI+"dBm",true,1000,true);

  //apaga led
  digitalWrite(pinoLed,LOW);
}

Tabela dBm

Exponho nesta tabela o quanto equivale uma unidade dBm em miliwatt.


Faça download dos arquivos:




Nenhum comentário:

Tecnologia do Blogger.