
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.
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…)
Anuncio:
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.
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.
Así, creamos un fichero llamado ‘ESP8266_Utils_OTA.hpp’ cuyo contenido es el siguiente.
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"); }
Este fichero contiene toda la lógica repetitiva del proceso OTA. Esto permite que 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(); }
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.
Seleccionamos este puerto de programación WiFi y volvemos a subir el fichero. Veremos que el proceso se muestra correctamente en el Arduino IDE.
Y, si tuviéramos conectado el ESP8266 a un ordenador veríamos la salida por puerto serie indicando asimismo el proceso.
¡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.
Versión para el ESP8266: https://github.com/luisllamasbinaburo/ESP8266-Examples
Versión para el ESP32: https://github.com/luisllamasbinaburo/ESP32-Examples
Anuncio:
Ostras es genial esto! He aplicado el OTA a uno de los ejemplos de la serie ESP8266, el del deslizador para el LED por PWM, y funciona a las mil maravillas, que pasada!! Con este artículo de OTA ya he terminado todos toditos. Me costó un poco el de python por la instalación e instalar la libreria serial, tuve que consultar un poco a youtube y luego ejecutar scripts, pero toditos, perfecto. Mis felicitaciones Luis!! Que sigan esos artículos que son una pasada! Gracias!!
En primer lugar agradecer el esfuerzo y el altruismo que aportas Luis. Soy un mero aficionadillo a los ESP y tus aportaciones son fundamentales para mí. Tengo un problema con el tema del OTA. He subido a mi ESP el ejemplo que propones, el 12_OTA, en el monitor serie veo, cuando reseteo el ESP, por qué IP se conecta, también me aparece OTA iniciado, todo correcto. Pero cuando voy a actualizar el sketch, habiendo desconectado USB-serie, no me aparece un nuevo puerto para poder hacerlo, como se supone que debería ocurrir. Todo esto lo hago desde Windows 10 He reinstalado… Read more »
Hola. Muchas gracias por toda esta información.
Me surge la siguiente duda: Es necesario que el ESP se encuentre dentro de la misma red a la cual está conectadoel ordendor desde el cual deseo actualizar? Es decir, con esta librería podría actualizar un sketch estando a unos cuantos miles de metros? Gracias