Projetos com Arduino/ESP

Índice

Algumas dicas

Credenciais de WiFi

Deprecated: usar WiFiManager + ArduinoOTA

Para que as credenciais não precisem ficar no mesmo arquivo INO nem nas mesmas pastas do projeto (o que levaria as credenciais a serem sincronizadas com um repositório, eventualmente), criar um arquivo credentials.h no diretório Arduino/libraries/Meslin. Esse diretório, no Linux fica em ~/Arduino/libraries/ e no Windows fica em C:\Users\meslin\Documents\Arduino\libraries\.

O conteúdo do arquivo deverá ser:

#define MY_SSID ("Seu SSID")

#define MY_PASSWORD ("A senha do WiFi")

Ao usar o WiFi, inclua o seguinte header no programa:

#include <credentials.h>

Programação usando OTA (On-The-Air)

Para programa o ESP32 via OTA é necessário que o Python versão 2 (testado com 2.7.18). O Python versão 3 pode estar instalado sem problemas, mas durante a instalação do Python 2 é necessário que a PATH seja modificada para incluir o Python. Essa opção está disponível durante a instalação.

A programação foi testada com a biblioteca ArduinoOTA e o exemplo ArduinoOTA/BasicOTA.

Como gravar ESP12F, ESP32, ESP32-CAM

Circuitos das Figuras A e D foram testados e funcionaram.

Deprecated para ESP12F, ESP32 - usar o programador.

Testado!

Lembrar de colocar a chave em 3.3V.

Teórico (?)

Teórico (?)

Testado!

Lembrar de colocar a chave em 5V.

Modelo Básico para ESP32/ESP8266

Inclui:


#include <WiFiManager.h> // https://github.com/tzapu/WiFiManager

#include <ArduinoOTA.h>


void setupArduinoOTA(void);

void setupWiFiManager(void);


void setup() {

 Serial.begin(115200);

 Serial.println("Booting");


 setupWiFiManager();

 setupArduinoOTA();


 pinMode(LED_BUILTIN, OUTPUT); // led blink

}


void loop() {

 ArduinoOTA.handle();


 // led blink

 digitalWrite(LED_BUILTIN, HIGH);  // turn the LED on (HIGH is the voltage level)

 delay(500);                       // wait for a second

 digitalWrite(LED_BUILTIN, LOW);   // turn the LED off by making the voltage LOW

 delay(1000);                      // wait for a second

}






/**

* setupWiFiManager

* Configura o WiFi Manager

* Utiliza o endereço IP 192.168.0.1

* SSID OTA-Template

* Não tem senha

*/

void setupWiFiManager(void) {

 // WiFiManager, Local initialization. Once its business is done, there is no need to keep it around

 WiFiManager wm;


 // reset settings - wipe stored credentials for testing

 // these are stored by the esp library

 // wm.resetSettings();


 // Automatically connect using saved credentials,

 // if connection fails, it starts an access point with the specified name ( "AutoConnectAP"),

 // if empty will auto generate SSID, if password is blank it will be anonymous AP (wm.autoConnect())

 // then goes into a blocking loop awaiting configuration and will return success result


 bool res;

 // Apagar as credenciais Wi-Fi armazenadas (descomente a linha abaixo para limpar)

 // wm.resetSettings();

 //set custom ip for portal

 wm.setAPStaticIPConfig(IPAddress(192,168,0,1), IPAddress(192,168,0,1), IPAddress(255,255,255,0));

 // res = wm.autoConnect(); // auto generated AP name from chipid

 // res = wm.autoConnect("AutoConnectAP"); // anonymous ap

 // res = wm.autoConnect("OTA-Template", "password"); // password protected ap

 res = wm.autoConnect("OTA-Template"); // no password protected


 if (!res) {

   Serial.println("Failed to connect");

   // ESP.restart();

 }

 else {

   // if you get here you have connected to the WiFi

   Serial.println("connected...yeey :)");

 }

}




/**

* setupArduinoOTA

* Configura o Arduino OTA para upload de código via Wi-Fi

* Porta 8266 (default)

* Host OTA-Template

* Sem senha

*/

void setupArduinoOTA(void) {

 // Port defaults to 8266

 // ArduinoOTA.setPort(8266);


 // Hostname defaults to esp8266-[ChipID]

 ArduinoOTA.setHostname("OTA-Template");


 // No authentication by default

 // ArduinoOTA.setPassword("admin");


 // Password can be set with it's md5 value as well

 // MD5(admin) = 21232f297a57a5a743894a0e4a801fc3

 // ArduinoOTA.setPasswordHash("21232f297a57a5a743894a0e4a801fc3");


 ArduinoOTA.onStart([]() {

   String type;

   if (ArduinoOTA.getCommand() == U_FLASH) {

     type = "sketch";

   } else {  // U_FS

     type = "filesystem";

   }


   // NOTE: if updating FS this would be the place to unmount FS using FS.end()

   Serial.println("Start updating " + type);

 });


 ArduinoOTA.onEnd([]() { Serial.println("\nEnd"); });


 ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {

   Serial.printf("Progress: %u%%\r", (progress / (total / 100)));

 });


 ArduinoOTA.onError([](ota_error_t error) {

   Serial.printf("Error[%u]: ", error);

   if (error == OTA_AUTH_ERROR) {

     Serial.println("Auth Failed");

   } else if (error == OTA_BEGIN_ERROR) {

     Serial.println("Begin Failed");

   } else if (error == OTA_CONNECT_ERROR) {

     Serial.println("Connect Failed");

   } else if (error == OTA_RECEIVE_ERROR) {

     Serial.println("Receive Failed");

   } else if (error == OTA_END_ERROR) {

     Serial.println("End Failed");

   }

 });


 ArduinoOTA.begin();

 Serial.println("Ready");

 Serial.print("IP address: ");

 Serial.println(WiFi.localIP());

}

Scanner de Dispositivos OTA

Esse programa deve ser utilizado para suprir a deficiência do Visual Studio Code em descobrir os dispositivos OTA na rede.


import socket

import struct


# Configurações do multicast

MULTICAST_GROUP = '224.0.0.251'  # Endereço do mDNS (ArduinoOTA usa multicast para anúncios)

PORT = 5353  # Porta padrão do mDNS (multicast DNS)

TIMEOUT = 20    # tempo de timeout para descobrir dispositivos OTA


def discover_arduino_ota_devices(timeout=5):

   """

   Descobre dispositivos ArduinoOTA na rede local.

   :param timeout: Tempo em segundos para escanear a rede.

   :return: Lista de dispositivos encontrados (endereço IP e nomes).

   """

   # Cria um socket UDP

   sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)

   sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

  

   # Adiciona o socket ao grupo multicast

   group = struct.pack('4sl', socket.inet_aton(MULTICAST_GROUP), socket.INADDR_ANY)

   sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, group)

  

   # Define um tempo limite para receber respostas

   sock.settimeout(timeout)

  

   # Envia uma mensagem multicast de descoberta

   query = (

       "\x00\x00"  # Transaction ID

       "\x00\x00"  # Flags

       "\x00\x01"  # Número de perguntas (1)

       "\x00\x00"  # Respostas

       "\x00\x00"  # Autoridade

       "\x00\x00"  # Adicional

       "\x08_arduino"  # Name: _arduino

       "\x04_tcp"      # Type: _tcp

       "\x05local"     # Domain: local

       "\x00"  # Fim do nome

       "\x00\x0C"  # Tipo: PTR (nome de domínio apontado)

       "\x00\x01"  # Classe: IN (Internet)

   ).encode('utf-8')


   sock.sendto(query, (MULTICAST_GROUP, PORT))

  

   devices = []

   try:

       print("Escaneando dispositivos...")

       while True:

           # Recebe respostas de dispositivos

           data, addr = sock.recvfrom(1024)


           # Decodifica o nome OTA do dispositivo da resposta (mDNS)

           device_name = extract_ota_name(data)

           if device_name:

               print(f"Dispositivo encontrado: IP={addr[0]}, Nome OTA={device_name}")

               devices.append((addr[0], device_name))

           else:

               print(f"Dispositivo encontrado: IP={addr[0]}, Nome desconhecido")

               devices.append((addr[0], "Nome desconhecido"))

   except socket.timeout:

       print("Fim do escaneamento.")


   sock.close()

   return devices


def extract_ota_name(data):

   """

   Extrai o nome OTA do dispositivo da resposta mDNS.

   :param data: Dados recebidos do dispositivo.

   :return: Nome do dispositivo (string) ou None.

   """

   try:

       # Localiza o nome do dispositivo na resposta mDNS

       response = data.decode(errors='ignore')

       if "_arduino\x04_tcp\x05local" in response:

           strBusca = "\x00\x00\x0C\x00\x01\x00\x00\x11\x00"

           start = response.find(strBusca)

           if start != -1:

               # Extrai o nome antes do domínio "_arduino._tcp.local"

               nome = response[start+len(strBusca)+2:start+len(strBusca)+2+ord(response[start+len(strBusca)+1:start+len(strBusca)+2])]

               segments = response.split("_arduino._tcp.local")

               if len(nome) > 0:

                   return nome

               else:

                   return None

   except Exception as e:

       print(f"Erro ao interpretar resposta mDNS: {e}")

   return None


# Descobre os dispositivos e lista os resultados

def main():

   devices = discover_arduino_ota_devices(timeout=TIMEOUT)

   print("\nDispositivos encontrados:")

   for device in devices:

       print(f" - {device}")

   return


if __name__ == '__main__':

   main()