2.2 WiFi – Archivo.ino para ESP8266/ESP32

Referencia: ESP8266WiFi library. https://esp8266-arduino-spanish.readthedocs.io/es/latest/esp8266wifi/readme.html

Las instrucciones se presentan paso a paso, en caso que realice por primera vez éste proceso, en los próximos ejemplos bloques y pasos básicos repetidos solo se mencionarán y/o se hará referencia a éste ejemplo.


1. Bloque de inicio

1.1 Librerías

Las librerias contienen las instrucciones para los procesos como el de conexión, manejo de datos como direcciones IP, MAC,  o niveles de señal RSSI, valores de estado de conexión, etc.

Las librerías podrían variar entre modelos de placas de desarrollo principalmente por tipo de módulo o microcontrolador, sin embargo las instrucciones son las mismas. La siguiente tabla muestra la librería usada en cada caso:

Modelo libreria
ESP8266 <ESP8266WiFi.h>
ESP32 <WiFi.h>

Para el resto de las instrucciones no hay diferencias, las instrucciones son  las mismas manteniendo el uso de pines de la placa.

Esta selección de librerias se puede realizar con inclusión de condigo condicionado por la placa mediante la instrucción #ifdef #elif #endif. De esta manera se puede realizar un solo código general, al compilar en arduino, dependiendo de la placa que se tiene conectada se selecciona la librería necesaria.

// detectar placa al compilar
# ifdef defined(ESP8266)
  #include <ESP8266WiFi.h>
# elif defined(ESP32)
  #include <WiFi.h>
# endif
WiFiClient wificlient;

Referencia: http://www.cplusplus.com/doc/tutorial/preprocessor/

1.2 Parámetros y cliente de la red

Como en toda conexión Wifi se require de: Un identificador de router ‘ssid‘ y Una contraseña ‘password‘. En las instrucciones del ejemplo son valores de la red que se deben actualizar para poder conectarse en cada caso particular.

// WIFI: conexión a Router
char* ssid = "miRouter";
char* password = "miRouterClave";

Con los parámetros anteriores, se inicializa el proceso conectarse a la red.

1.3 Pines a usar – Estado de conexión por parpadeo de LED

Para una versión simplificada de prueba de estado de conexión,se usan el parpadeo del LED incorporado en la placa de desarrollo, dado por el pin del modelo de placa usado (Revisar la hoja de datos)-

int LED_pin=2;

En el bloque de inicio también se establecen valores para otros parámetros. Las placas de desarrollo facilitan esta opción al encontrarse conectadas por el cable USB, por lo que se añade la opción de activar mensajes en cada bloque con la bandera serial_msg = true.

En el caso de que ya no se requieran, se destartan las instrucciones de mensajes usando el valor bandera serial_msg = false. También se usa esta opción con los módulos compactos como el ESP01, que no posible usar mensajes por USB por lo limitado de pines disponibles.


2. Bloque de configuración – setup()

El dispositivo se inicializa con el bloque setup(), primero indicando el modo uso como salida de pin LED_pin.

void setup() {
  if (serial_msg){
    Serial.begin(115200); //115200,74880
  }
  
  // LED interno, Enciende en LOW
  pinMode(LED_pin, OUTPUT);

  // conexión WIFI
  inicia_wifi();
}

Luego sigue las instrucciones del procedimiento inicia_wifi(), dedicada a establecer la conexión con el router. En teoría se debería ejecutar solo una vez, sin embargo podría requerir conexión, por ejemplo ante una falla de energía eléctrica en el sector.


3. Bucle o lazo de operación – loop()

La operación del dispositivo se realiza siguiendo las instrucciones del bucle ‘loop()’

El primer paso es verificar si se ha logrado una conexión, de no ser el caso, se repite el procedimientoinicia_wifi()en el que se realizan varios intentos previo a retomar las instrucciones para no dejar sin atender el resto de la operación del dispositivo, por ejemplo la lectura periódica de sensores.

Luego se tiene el bloque de parpadeo de LED como única operación del dispositivo.

Para la versión de placa con ESP8266, se usa la instrucción yield() que cede tiempo de procesamiento al microcontrolador para procesar los detalles de la parte inalámbrica, pues el ESP8266 se tiene un solo núcleo y los procesos se realizan en tiempo compartido.

En el caso de ESP32 que tiene dos núcleos, un núcleo se dedica a la parte del manejo inalámbrico, por lo que no es necesaria la instrucción anterior.

4. Procedimientos y Funciones

Los pasos para conexión al Router y reconexión se pueden requerir más de una vez, por lo que se separan en un procedimiento denominado inicia_wifi(){ }.

En esta sección se define el modo como estación para la conexión del dispositivo y se procede a la llamada del proceso inicial de conexión de la librería WiFi.

  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);

Se requiere de un intervalo de tiempo determinado por la variable espera para obtener el resultado del proceso y establecido en al menos 10.

En éste proceso el parpadeo del LED se definide en la tabla para «NO conectado» en la pagina anterior como 300 ms encendido  y 200 ms apagado.

Cuando se establece la conexión y se dispone de la bandera serial_msg = true, se puede mostrar los valores para algunos parámetros en la red como estado, MAC, IP, RSSI.

if (WiFi.status() == WL_CONNECTED){
      Serial.print(" Estado: ");
      Serial.println(WiFi.status());
      Serial.print(" MAC: ");
      Serial.println(WiFi.macAddress());
      Serial.print(" IP: ");
      Serial.println(WiFi.localIP());
      Serial.print(" RSSI: ");
      Serial.println(WiFi.RSSI());
      Serial.print(" Canal: ");
      Serial.println(WiFi.channel());
      Serial.println();
      }

5. Instrucciones en Arduino IDE

Se compone de dos secciones separadas en pestañas: la sección principal y la de procedimiento de inicia_wifi().

5.1 Sección principal

/* WIFI Blink Ejemplo de conexión a WiFi con ESP8266/ESP32  
 * edelros@espol.edu.ec 2019
*/
// detectar placa al compilar
# ifdef defined(ESP8266)
  #include <ESP8266WiFi.h>
# elif defined(ESP32)
  #include <WiFi.h>
# endif
WiFiClient wificlient;

// WIFI: conexión a Router
char* ssid = "miRouter";
char* password = "miRouterClave";

// LED interno, ESP01-pin=1, ESP07-pin=2
int LED_pin = 2;

// Mensajes por Puerto Serial. ESP01 usar false
volatile boolean serial_msg = true;

void setup() {
  if (serial_msg){
    Serial.begin(115200); //115200,74880
  }
  
  // LED interno, Enciende en LOW
  pinMode(LED_pin, OUTPUT);

  // conexión WIFI
  inicia_wifi();
}

void loop() {
  
  // Conectado, LED Parpadea, enciende en LOW
  if (WiFi.status() == WL_CONNECTED){
    digitalWrite(LED_pin, LOW);
    delay(1000); // un segundo
    
    #ifdef defined(ESP8266)
      yield();
    #endif
    
    digitalWrite(LED_pin, HIGH);
    delay(1000);
    }
    
  if (WiFi.status() != WL_CONNECTED){
    digitalWrite(LED_pin, LOW);
    delay(300);
    digitalWrite(LED_pin, HIGH);
    delay(200);
    
    #ifdef defined(ESP8266)
      yield();
    #endif
    }

  // WiFi reconectar si está inactivo
  if (WiFi.status() != WL_CONNECTED){
    inicia_wifi();
  }
}

5.2 Otras pestañas o procedimientos

Proceso en otra pestaña: wifi_inicia a continuación de las instrucciones anteriores.

Nota: Se ha usado el nombre de pestaña con las palabras intercambiadas para distinguir entre pestaña y procedimiento.

void inicia_wifi(){
  int espera = 10; // >=10 para conectar
  int cuenta = 0;

  // mensajes por serial activado
  if (serial_msg){
    Serial.print(" WIFI Conectando a ");
    Serial.println(ssid);
    }

  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  
  while ((WiFi.status()!=WL_CONNECTED)&&(cuenta<espera)){  
    cuenta = cuenta+1;
    
    // Parpadeo de Monitor enciende en LOW
    digitalWrite(LED_pin, LOW);
    delay(300);
    digitalWrite(LED_pin, HIGH);
    delay(200);
    
    if (serial_msg){
      Serial.print(".");
      }
    }
    
  //activado mensajes por serial
  if (serial_msg){
    //Fin de "..."
    Serial.println();
    if (WiFi.status() == WL_CONNECTED){
      Serial.print(" Estado: ");
      Serial.println(WiFi.status());
      Serial.print(" MAC: ");
      Serial.println(WiFi.macAddress());
      Serial.print(" IP: ");
      Serial.println(WiFi.localIP());
      Serial.print(" RSSI: ");
      Serial.println(WiFi.RSSI());
      Serial.println();
      }
    if (WiFi.status() != WL_CONNECTED){
      WiFi.printDiag(Serial);
      Serial.println();
      }
    }
  }

6. Compilar y subir las instrucciones

Una vez terminado el archivo de instrucciones, se graba en un directorio de trabajo, por ejemplo c:\IoT_Taller, con un nombre simple, sin espacios ni tildes, la extensión del archivo.ino se añade de forma automática.

Antes de realizar el proceso de envio del archivo compilado a la placa, verifique que se encuentra seleccionada la placa de desarrollo que está usando: ESP8266 o ESP32 en el menú de Herramientas/Placa.

Verifique que se ha seleccionado el ‘Puerto COM’ donde se encuentra conectada la placa usando el menú de herramientas, puerto asignado, semejante a lo mostrado en la figura.

Para pasar las instrucciones a la placa de desarrollo se usa el botón «subir», en el proceso primero se verifica que no existan errores o inconsistencias de sintaxis. De estar las instrucciones en orden, se transfieren al dispositivo.

En el caso de la placa ESP32 se requiere que se presione también el botón BOOT de la placa de desarrollo. En la versión ESP8266 este paso no es necesario.

En la parte inferior de la ventana se muestran mensajes del proceso de comunicación entre el computador y la placa de desarrollo,

Al terminar se reinicia por si misma la placa de desarrollo y se muestra el resultado de las instrucciones.

7. Estados de conexión con mensajes a puerto serial

Durante el desarrollo es favorable disponer de mensajes en el computador que muestren los estados o valores de las variables para una revisión paso a paso de lo que sucede en el dispositivo.

Las placas de desarrollo facilitan esta opción al encontrarse conectadas por el cable USB, por lo que se añade la opción de activar mensajes en cada bloque con la bandera serial_msg = true

Al inicializar el dispositivo se indica la velocidad de comunicación entre el dispositivo y el computador por el puerto USB mediante la instrucción:

Serial.begin(74880)

en adelante lo que se usa es mostrar un mensaje o valor de variable con las instrucciones:

    Serial.print(" WIFI Conectando a ");
    Serial.println(ssid);

obteniendo los resultados en la ventana del computador obtenida en el menú «Herramientas/Monitor Serie»

3.2 Resultado de mensajes recibidos en «Monitor Serie» con Arduino IDE

Se obtiene unos resultados semejantes a los mostrados en la ventana

..........
Mode: STA
PHY mode: N
Channel: 6
AP id: 0
Status: 1
Auto connect: 1
SSID (15): miRouter
Passphrase (10): miRouterClave
BSSID set: 0

 WIFI Conectando a miRouter
.........
 Estado: 3
 MAC: 2C:3A:E8:0A:98:66
 IP: 192.168.10.11
 RSSI: -74

Hasta aqui el proceso de las instrucciones para conexión, detallada paso a paso la estructura de programación, librerias y parámetros usados.

Las siguientes secciones amplian la funcionalidad del dispositivo conectandose con los otros componentes del esquema de IOT, añadiendo manejar mensajes hacia un broker y la gestión de los estados.

2.1. WiFi – Esquema de instrucciones por Bloques

Proceso de conexión a un Router WiFi

Se desarrolla el primer paso del proceso, que tiene como objetivo conectar el dispositivo a la red de datos WiFi.


Las placas de desarrollo ESP8266/ESP32 tienen un LED incorporado que puede ser usado para el propósito de disponer de un medio de observación de estado de «conectado» o «NO conectado»en el ejercicio.

1.1 Estado – Conectado / NO conectado

El estado de Conectado a Wifi  se puede mostrar con un parpadeo LENTO del LED, encendido por un segundo  y apagado en el siguiente segundo, es decir un periodo total de 2 segundos.

Para el proceso de Inicio de conexión  a Wifi, el parpadeo del LED puede ser más RAPIDO y actua como indicador de estado del dispositivo.

En un microcontrolador el tiempo se marca en milisegundos, por lo que los valores a usar en cada estado del proceso se indican en ms en la siguiente tabla.

Estado Conectado No conectado
LED encendido 1000 ms 300 ms
LEd Apagado 1000 ms 200 ms
LENTO RAPIDO

El LED incorporado en la placa de desarrollo se direcciona o activa por medio de un PIN de la placa. El Pin predeterminado de la placa de desarrollo ESP8266 y ESP32 es el PIN 2, que como no requiere conexión adicional solamente se indica al inicio de las instrucciones.

int LED_pin = 2;

1.2 Parámetros de la red WiFi

Como en toda conexión a WiFi realizada con el computador o el móvil, se require dos parámetros:

parámetro variable valor ejemplo
identificador de router ssid "miRouter"
contraseña password "miRouterClave"

Los valores mostrados son de ejemplo, en su caso particular debe sustituir con los valores de la red que requiera conectarse.

2. Esquema de Instrucciones para el dispositivo

Las intrucciones para un microcontrolador usan tres bloques principales: inicio, configuración setup(), bucle o lazo de operación loop().

El bloque de inicio contiene las librerias de los procesos y funciones que se usaran en la operación del dispositivo, establecen  los parámetros de uso de los PINes de entrada y salida, parámetros de la red que se describieron en el numeral anterior. Adicionalmente contiene comentarios referentes al uso de las instrucciones, autor, etc.

El bloque de configuración, tambien conocido como setup(), usa los parámetros del bloque de inicio para configurar el dispositivo al arrancar, cuando se energiza o reinicia. Establece el tipo de uso de cada PIN, como entrada o salida, inicia los procesos de operación que requieren ser llamados una sola vez.

El bucle o lazo de operación, también conocido como loop(), es un lazo infinito que se encarga del comportamiento del dispositivo de acuerdo a las instrucciones dadas. Lo de lazo infinito se usa en el contexto que mientras el dispositivo tenga energía, esté conectado o no se reinicie.

/* Bloque de inicio 
 *  donde van las librerias, parámetros
 *  variables globales
 */
void setup() {
  // instrucciones de configuración inicial
  // funcionan una sola vez al encender el dispositivo

}

void loop() {
  // instrucciones de operación del dispositivo

}

void inicia_wifi(){
  // procedimientos o funciones que se repiten
  // en los bloques anteriores ej: conectar/reconectar
  // a WiFi, lectura de sensores, manejo de mensajes MQTT
  
}

Dado que durante el proceso de operación pueden ocurrir desconexiones a la red WiFI, podría ser necesario reiniciar el proceso de conexión. Los procesos que se repiten o se dedican a un propósito particular se realizan aparte.

Ante una situación de desconexión, al inicio del bucle de operación se realiza la revisión del estado de conexión para de no tener estado de «conectado» se realice el proceso nuevamente con varios intentos antes de proceder a atender las actividades normales de operación como la lectura de sensores.

La instrucción yield() cede tiempo de procesamiento del microcontrolador para procesar detalles de la parte inalambrica. Esta operación se usa con ESP8266 pues se tiene un solo núcleo y las operaciones trabajan en tiempo compartido.

En el caso de ESP32 que tiene dos núcleos, un núcleo se dedica a la parte del manejo inalámbrico, por lo que no es necesaria la instrucción yield().

3. Instrucciones con uso de pestañas en Arduino IDE

Cuando las instrucciones son numerosas, muchas líneas, existen varios bloques de procedimientos y funciones, se usan bloques que los agrupan en  pestañas. Esto simplifica la lectura de las instrucciones y permite enfocarse en sus partes en lugar de tener todas en una misma hoja.

La parte principal del algoritmo se escribe en la primera pestaña, que tiene el mismo nombre que el archivo. Para añadir pestañas se dispone de un botón a la derecha de la barra, marcado en la figura con rojo.