como-programar-el-esp8266-por-wifi-con-arduino-ota

Cómo programar el ESP8266 o ESP32 por WiFi con Arduino OTA

Hacemos una pequeña pausar en las entradas del ESP8266 y el ESP32 como servidor para ver una de las funcionalidades más interesantes, la programación OTA.

Haremos referencia al ESP8266, pero el mismo código es compatible para el ESP32, ajustando el nombre de las librerías. Al final tenéis el código tanto para el ESP8266 como para el ESP32.

En las entradas anteriores hemos visto las formas de conexión del ESP8266 (AP, STA), el ESP8266 actuando cómo cliente, y varias entradas con el ESP8266 como servidor.

La programación OTA (Over The Air) es una funcionalidad muy interesante que nos permite cargar el firmware o los ficheros del SPIFFS del ESP8266 a través de una conexión Wi-Fi, en lugar del habitual puerto serie.

Esto nos permite reprogramar el ESP8266 sin tener acceso físico, o necesidad de conectarnos al módulo con un cable. Por supuesto, es una funcionalidad muy interesante cuando pongamos uno de estos módulos en una instalación permanente (imaginaros que está detrás de un mueble, dentro de una caja, o pegado al techo…)

Afortunadamente, la programación OTA es muy sencilla gracias a la librería ArduinoOTA, que también se encuentra integrada en la definición de hardware del ESP8266 que instalamos para poder programar el ESP8266 desde el Arduino IDE.

La programación OTA puede realizarse desde el propio Arduino IDE, desde IDEs basados en el (Visual Studio Micro, Visual Studio Code, PlatformIO… ) o directamente por Web. En esta entrada veremos la primera de ellas, desde el propio Arduino IDE.

Para que la programación OTA funcione en el ESP8266 en el IDE Arduino es necesario que tengamos Python instalado. Si aún no lo habéis hecho, aquí tenéis un tutorial.

Además, para que la programación OTA funcione es necesario que el ESP8266 disponga del doble de memoria ocupada por el programa que vamos a subir. Esto es así porque, por seguridad, el programa se sube a la memoria temporalmente. Cuando la carga ha terminado, se vuelca a la memoria flash.

Librería Arduino OTA

Como decíamos, la “magia” de la programación por WiFi recae en la librería Arduino OTA, que dispone de todas las funciones que necesitamos para gestionar el proceso.

El primer lugar, es necesario inicializar la librería con la función

//Starts the ArduinoOTA service
void begin(bool useMDNS = true);

Posteriormente, en el bucle principal debemos llamar a la función que se encarga de gestionar el OTA si se recibe una petición de programación.

//Call this in loop() to run the service. Also calls MDNS.update() when begin() or begin(true) is used.
void handle();

Por otro lado, la librería proporciona distintas función de callback cuando ocurren ciertos eventos en el proceso OTA.

//This callback will be called when OTA connection has begun
void onStart(THandlerFunction fn);

//This callback will be called when OTA has finished
void onEnd(THandlerFunction fn);

//This callback will be called when OTA encountered Error
void onError(THandlerFunction_Error fn);

//This callback will be called when OTA is receiving data
void onProgress(THandlerFunction_Progress fn);

En ocasiones, puede ser importante añadir acciones en estos eventos. Por ejemplo, en el caso de una máquina que controla un proceso, este va a quedar “suspendido” mientras se produce la reprogramación OTA.

Por tanto, sería necesario añadir las acciones oportunas para que el proceso se desarrolle con seguridad (por ejemplo, parando los motores, o llevando la máquina a una posición segura).

Adicionalmente, se dispone de la función ‘getCommand()’ que funciona mientras el proceso OTA se ha iniciado, nos permite distinguir si el proceso OTA es del firmware (Flash) o del sistema de archivos (FS).

//Gets update command type after OTA has started. Either U_FLASH or U_FS
int getCommand();

Otra cuestión importante es la relativa a la seguridad porque, lógicamente, en muchas ocasiones no queremos que cualquier pueda reprogramar nuestra placa. Por tanto, la librería ArduinoOTA permite añadir un password para autentificar el proceso OTA.

//Sets the password that will be required for OTA. Default NULL
void setPassword(const char *password);

//Sets the password as above but in the form MD5(password). Default NULL
void setPasswordHash(const char *password);

Finalmente, la librería proporciona las siguientes funciones relacionadas con el OTA,

//Sets the service port. Default 8266
void setPort(uint16_t port);

//Sets the device hostname. Default esp8266-xxxxxx
void setHostname(const char *hostname);
String getHostname();

//Sets if the device should be rebooted after successful update. Default true
void setRebootOnSuccess(bool reboot);

Ejemplo de programación OTA

Una vez visto en detalle la librería ArduinoOTA en su implementación para el ESP8266 toca verlo todo con un ejemplo. Como de costumbre, vamos a dividir el código en ficheros para mejorar la reutilización y mantenibilidad.

Nuestro Sketch principal queda tan sencillo como

#include <ESP8266WiFi.h>
#include <ArduinoOTA.h>

#include "config.h"  // Sustituir con datos de vuestra red
#include "ESP8266_Utils.hpp"
#include "ESP8266_Utils_OTA.hpp"

void setup(){
  Serial.begin(115200);

  ConnectWiFi_STA();

  InitOTA();
}

void loop(){
  ArduinoOTA.handle();
}

Un fichero llamado ‘ESP8266_Utils_OTA.hpp’. Este fichero contiene toda la lógica repetitiva del proceso OTA.

void InitOTA()
{
// Port defaults to 8266
// ArduinoOTA.setPort(8266);

// Hostname defaults to esp8266-[ChipID]
// ArduinoOTA.setHostname(hostname);

// 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_SPIFFS
    type = "filesystem";
  }

  // NOTE: if updating SPIFFS this would be the place to unmount SPIFFS using SPIFFS.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("");
Serial.println("OTA iniciado");
}

Resultado

Cargamos el programa en el ESP8266 como habitualmente, a través del puerto serie. Ahora, ya podemos soltar el cable del ordenado y dejarlo conectado únicamente a una fuente de alimentación (por ejemplo, un cargador de móvil, una batería, etc…)

Por otro lado reiniciamos el Arduino IDE. Al volverlo a iniciar, veremos que tenemos un nuevo “puerto” de programación.

esp8266-OTA-arduino-ide

Seleccionamos este puerto de programación WiFi y volvemos a subir el fichero. Veremos que el proceso se muestra correctamente en el Arduino IDE.

esp8266-OTA-uplading

Y, si tuviéramos conectado el ESP8266 a un ordenador veríamos la salida por puerto serie indicando asimismo el proceso.

esp8266-OTA-uploading-process

Es importante que recordemos añadir la funcionalidad OTA en el firmware nuevo firmware que subamos o perderemos la capacidad de programación OTA.

¡Así de sencillo! En general, el proceso es bastante sencillo y muy robusto (a mí nunca me ha fallado). Ahora podéis usar la programación WiFi para probar vuestros ejemplos, subiendo tanto firmware como ficheros del SPIFFS.

En las próximas entradas nos adentraremos en las funcionalidades del ESP8266 como servidor, aprendiendo cómo enviar datos desde el cliente al ESP8266 a través de un formulario.

Descarga el código

Todo el código de esta entrada está disponible para su descarga en Github.

github-full

Versión para el ESP8266: https://github.com/luisllamasbinaburo/ESP8266-Examples

Versión para el ESP32: https://github.com/luisllamasbinaburo/ESP32-Examples