19 de setembro de 2021

Do bit Ao Byte

Embarcados, Linux e programação

Configurar ethernet e WiFi da T-Internet-PoE

t-internet-poe | ethernet e wifi | roteamento

No artigo anterior expus o setup incompleto do modo bridge da T-Internet-PoE. Para não ficar uma lacuna, decidi escrever esse artigo que foi um dos testes que fiz para comprovar o funcionamento das interfaces ethernet e wifi.

Interfaces ethernet e WiFi independentes

Nessa configuração temos ambas as interfaces funcionando, porém independentes. Isso significa que se a WiFi estiver configurada em modo AP, não adianta se conectar a ela para tentar navegar diretamente. Mas pode ser uma excelente opção para usar como barreira, no estilo proxy.

Proxy

Que eu me lembre, nunca escrevi sobre proxy, nem aqui nem para outro blog. A razão é que a documentação Squid Ninja contempla absolutamente todas as configurações do proxy Squid, que usei bastante no início dos anos 2000 para fazer cache, aumentando assim a velocidade de navegação, mas também usei para controle de acesso a sites. No nosso caso, o papel da T-Internet-PoE seria parecido nesse segundo recurso; controlar o acesso. E de que forma?

Terceirizar requisições

Suponhamos que haja um serviço rodando em nuvem e nossa placa T-Internet-PoE é quem faz a consulta e entrega para os dispositivos requisitantes (ou envia a solicitação dos dispositivos requisitantes). Por exemplo, mandar status para a nuvem; um outro ESP32 da rede manda um json com a telemetria, juntamente com sua identificação (“JARDIM”, por exemplo). A T-Internet-PoE verifica se “JARDIM” é permitido, recebe o json e repassa. Desse modo, se alguém tentar passar dados maliciosos, será barrado antes de sair para a Internet. Claro que outros propósitos para essa placa são possíveis, esse foi um mero exemplo do uso das interfaces ethernet e wifi simultaneamente.

Configuração WiFi AP e ethernet

Sem mais delongas, vamos ao ponto. Primeiro, às bizarrices.

Para programar essa placa tive que testar “várias” opções de ESP32. A única que funcionou, ironicamente foi a OLIMEX ESP32-PoE. Escolha “essa” placa para fazer upload pela IDE do Arduino.

O código de exemplo é oficial, mas com uma leve mexida. Como conectei a placa à ethernet do meu laptop, tive que instalar um servidor web para fazer o get a partir do sketch. No Linux, instalei o nginx:

sudo apt-get install nginx

Automaticamente um servidor web rodará na porta 80 com a mensagem padrão do servidor. Isso já é o suficiente para esse teste. O modo AP testei conectando a partir do smartphone.

Tive que configurar um servidor DHCP também para atribuir IP à interface ethernet. Não vou entrar em detalhes, se quiser ver como configurar um servidor DHCP facinho, dê uma olhada nesse artigo sobre o DNSMasq.

O código para configurar a ethernet e wifi é esse:

/*
    This sketch shows how to configure different external or internal clock sources for the Ethernet PHY
*/

#include <ETH.h>
#include <SPI.h>
#include <SD.h>
#include <WiFi.h>

#define SD_MISO         2
#define SD_MOSI         15
#define SD_SCLK         14
#define SD_CS           13
/*
   * ETH_CLOCK_GPIO0_IN   - default: external clock from crystal oscillator
   * ETH_CLOCK_GPIO0_OUT  - 50MHz clock from internal APLL output on GPIO0 - possibly an inverter is needed for LAN8720
   * ETH_CLOCK_GPIO16_OUT - 50MHz clock from internal APLL output on GPIO16 - possibly an inverter is needed for LAN8720
   * ETH_CLOCK_GPIO17_OUT - 50MHz clock from internal APLL inverted output on GPIO17 - tested with LAN8720
*/
// #define ETH_CLK_MODE    ETH_CLOCK_GPIO0_OUT          // Version with PSRAM
#define ETH_CLK_MODE    ETH_CLOCK_GPIO17_OUT            // Version with not PSRAM

// Pin# of the enable signal for the external crystal oscillator (-1 to disable for internal APLL source)
#define ETH_POWER_PIN   -1

// Type of the Ethernet PHY (LAN8720 or TLK110)
#define ETH_TYPE        ETH_PHY_LAN8720

// I²C-address of Ethernet PHY (0 or 1 for LAN8720, 31 for TLK110)
#define ETH_ADDR        0

// Pin# of the I²C clock signal for the Ethernet PHY
#define ETH_MDC_PIN     23

// Pin# of the I²C IO signal for the Ethernet PHY
#define ETH_MDIO_PIN    18

#define NRST            5
static bool eth_connected = false;


const char* ssid = "ESP32AP";
const char* passwd =  "12345678";



void WiFiEvent(WiFiEvent_t event)
{
    switch (event) {
    case SYSTEM_EVENT_ETH_START:
        Serial.println("ETH Started");
        //set eth hostname here
        ETH.setHostname("esp32-ethernet");
        break;
    case SYSTEM_EVENT_ETH_CONNECTED:
        Serial.println("ETH Connected");
        break;
    case SYSTEM_EVENT_ETH_GOT_IP:
        Serial.print("ETH MAC: ");
        Serial.print(ETH.macAddress());
        Serial.print(", IPv4: ");
        Serial.print(ETH.localIP());
        if (ETH.fullDuplex()) {
            Serial.print(", FULL_DUPLEX");
        }
        Serial.print(", ");
        Serial.print(ETH.linkSpeed());
        Serial.println("Mbps");
        eth_connected = true;
        break;
    case SYSTEM_EVENT_ETH_DISCONNECTED:
        Serial.println("ETH Disconnected");
        eth_connected = false;
        break;
    case SYSTEM_EVENT_ETH_STOP:
        Serial.println("ETH Stopped");
        eth_connected = false;
        break;
    default:
        break;
    }
}

void testClient(const char *host, uint16_t port)
{
    Serial.print("\nconnecting to ");
    Serial.println(host);

    WiFiClient client;
    if (!client.connect(host, port)) {
        Serial.println("connection failed");
        return;
    }
    client.printf("GET / HTTP/1.1\r\nHost: %s\r\n\r\n", host);
    while (client.connected() && !client.available());
    while (client.available()) {
        Serial.write(client.read());
    }

    Serial.println("closing connection\n");
    client.stop();
}

void setup()
{
    Serial.begin(115200);
    WiFi.mode(WIFI_MODE_AP);
    WiFi.softAP(ssid, passwd);

    WiFi.onEvent(WiFiEvent);
/*
    SPI.begin(SD_SCLK, SD_MISO, SD_MOSI, SD_CS);
    if (!SD.begin(SD_CS)) {
        Serial.println("SDCard MOUNT FAIL");
    } else {
        uint32_t cardSize = SD.cardSize() / (1024 * 1024);
        String str = "SDCard Size: " + String(cardSize) + "MB";
        Serial.println(str);
    }*/

    pinMode(NRST, OUTPUT);
    digitalWrite(NRST, 0);
    delay(200);
    digitalWrite(NRST, 1);
    delay(200);
    digitalWrite(NRST, 0);
    delay(200);
    digitalWrite(NRST, 1);


    ETH.begin(ETH_ADDR, ETH_POWER_PIN, ETH_MDC_PIN, ETH_MDIO_PIN, ETH_TYPE, ETH_CLK_MODE);
}


void loop()
{
    if (eth_connected) {
        testClient("192.168.1.200", 80);
    }
    delay(10000);
}

Aqui comentei o código relacionado ao SD card, que é o menos importante nesse momento. Faça upload para a placa e abra o monitor serial para ver a saída do get (1 vez a cada 10 segundos):

ethernet e wifi

Bem, agora já temos um diagnóstico positivo do funcionamento das interfaces e podemos ver também que a implementação é simples!