21 de marzo de 2020

NodeMCU: 07_ESPNOW (Comunicación bidireccional) ¡¡EUREKA!!

Entro ahora en terreno desconocido. No he leído nada, por ahora, que me permita hacer una comunicación ESP-NOW de forma bidireccional con los ESP8266, aunque puedo obtener pistas de la entrada NodeMCU: 04_ESPNOW (Comunicación maestro-esclavo).

La idea y paso previo


La idea es conectar un NodeMCU a un LED en D1 y a un pulsador en D0. Y asimismo otro segundo NodeMCU. Cuando pulse el pulsador del primer NodeMCU debe iluminarse el LED del segundo, y viceversa. Vamos, este circuito para ambos:



Para probar que está todo bien conectado... Así, si pulsamos el botón, se enciende el LED del NodeMCU.

int entrada = D0;
int salida = D1;
void setup() {
pinMode(entrada,INPUT);
pinMode(salida,OUTPUT);
}
void loop() {
digitalWrite(salida,digitalRead(entrada));
}

Y ahora el desafío: al pulsar el pulsador, se debe encender el LED del otro NodeMCU...

= = = = = = = = = = = 

El programa del primer NodeMCU

En este programa tenemos que hacer dos cosas (respecto a comunicaciones master-slave ESPNOW anteriores), que son:
  1. Utilizar el role 3 --> esp_now_set_self_role(3); 
  2. Utilizar la MAC de la otra estación en la línea de emparejamiento (esp_now_add_peer) y en el envío de datos (esp_now_send).
  3. Utilizar el callback de envío (esp_now_register_send_cb) y también el de recepción (esp_now_register_recv_cb), y en este último, programar los resultados. En mi caso, encender un LED.
Una vez comprendido el sistema, podremos hacer maravillas conectando ambos dispositivos. Habrá que ver cómo hacer para conectar más de uno... 

/* Este ejemplo intenta recopilar lo aprendido de esquemas anteriores
* y comunicará dos NodeMCU station "hablando" entre ellos.
* La acción en uno, establecerá una reacción en el otro.
*/
#include <ESP8266WiFi.h>
extern "C" {
#include <espnow.h>
}
//***ESTRUCTURA DE LOS DATOS TRANSMITIDOS ENTRE LAS UNIDADES***//
// Se establecerá IGUAL en todas
struct ESTRUCTURA_DATOS {
int estado; // 0 --> apagado , 1 --> encendido
};
// variables de elementos hardware
int entrada = D0; // pulsador
int salida = D1; // LED
// *****
// SETUP
// *****
void setup() {
//***INICIALIZACIÓN DEL PUERTO SERIE***//
Serial.begin(115200); Serial.println();Serial.println();
//*** pinMode ***
pinMode(entrada,INPUT);
pinMode(salida,OUTPUT);
//***INICIALIZACIÓN DEL PROTOCOLO ESP-NOW***//
if (esp_now_init()!=0) {
Serial.println("*** ESP_Now init failed");
ESP.restart();
delay(1);
}
//***DATOS DE LAS MAC (Access Point y Station) del ESP***//
Serial.print("Access Point MAC de este ESP: "); Serial.println(WiFi.softAPmacAddress());
Serial.print("Station MAC de este ESP: "); Serial.println(WiFi.macAddress());
//***DECLARACIÓN DEL PAPEL DEL DISPOSITIVO ESP EN LA COMUNICACIÓN***//
//0=OCIOSO, 1=MAESTRO, 2=ESCLAVO y 3=MAESTRO+ESCLAVO
esp_now_set_self_role(3); // Sería como maestro y esclavo a la vez
//***EMPAREJAMIENTO CON EL ESCLAVO***//
// Dirección MAC del ESP con el que se empareja (esclavo)
// Se debe introducir la STA MAC correspondiente
uint8_t mac_addr[6] = {0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff}; // STA MAC esclavo
uint8_t role=2;
uint8_t channel=3;
uint8_t key[0]={}; //no hay clave
//uint8_t key[16] = {0,255,1,1,1,1,1,1,1,1,1,1,1,1,1,1};
uint8_t key_len=sizeof(key);
Serial.print("Tamaño de *key: "); Serial.println(key_len);
esp_now_add_peer(mac_addr,role,channel,key,key_len);
}
// *******
// LOOP
// *******
void loop() {
// ---------------------------------------------------------------------------------
// ENVÍO: como Master
// ---------------------------------------------------------------------------------
//***DATOS A ENVIAR***//
ESTRUCTURA_DATOS ED;
ED.estado = digitalRead(entrada);
Serial.print("Dato pulsado: "); Serial.print(ED.estado);
delay(20);
//***ENVÍO DE LOS DATOS***//
//uint8_t *da=NULL; //NULL envía los datos a todos los ESP con los que está emparejado
uint8_t mac_addr[6] = {0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff}; // STA MAC esclavo
uint8_t data[sizeof(ED)]; memcpy(data, &ED, sizeof(ED));
uint8_t len = sizeof(data);
esp_now_send(da, data, len);
delay(1); //Si se pierden datos en la recepción se debe subir este valor
// *** CALLBACK de datos ENVIADOS ***
// *** Verificamos que los datos se han enviado....
esp_now_register_send_cb([](uint8_t* mac, uint8_t status) {
char MACesclavo[6];
sprintf(MACesclavo,"%02X:%02X:%02X:%02X:%02X:%02X",mac[0],mac[1],mac[2],mac[3],mac[4],mac[5]);
Serial.print(". Enviado a ESP MAC: "); Serial.print(MACesclavo);
Serial.print(". Recepcion (0=0K - 1=ERROR): "); Serial.println(status);
});
// ---------------------------------------------------------------------------------
// ---------------------------------------------------------------------------------
// Recepción: como Esclavo
// ---------------------------------------------------------------------------------
esp_now_register_recv_cb([](uint8_t *mac, uint8_t *data, uint8_t len) {
char MACmaestro[6];
sprintf(MACmaestro, "%02X:%02X:%02X:%02X:%02X:%02X",mac[0],mac[1],mac[2],mac[3],mac[4],mac[5]);
Serial.print("Recepcion desde ESP MAC: "); Serial.print(MACmaestro);
ESTRUCTURA_DATOS ED2;
memcpy(&ED2, data, sizeof(ED2));
Serial.print(". Dato estado: "); Serial.print(ED2.estado);
digitalWrite(salida,ED2.estado);
});
// ---------------------------------------------------------------------------------
}

El programa del segundo NodeMCU


Es idéntico al primero. Lo único que cambia es que ahora el primer NodeMCU es la estación (STA) vista desde el segundo (AP), así que hay que poner la STA MAC del primero en esp_now_add_peer y esp_now_send.

= = = = = = = = = = = =

NOTA: en estos días de confinamiento forzoso, con la amenaza de una enfermedad infecciosa en las puertas, este resultado me ha puesto muy contento. ¡¡Por fin lo he entendido!!

20 de marzo de 2020

NodeMCU: 04_ESPNOW (Comunicación maestro-esclavo)

Intentando la comunicación ESP-NOW, me propongo hacer el esquema que propone Dani No en su web de esploradores. Intentaremos la conexión master + esclavo para después poder intentar hacer la master+esclavo en ambos dispositivos

Primero, averiguamos las MACS.


Según Dani No, cada dispositivo posee dos MACs distintas. Una para las comunicaciones como AP (AP MAC) y otra como station (STA MAC). Para averiguarlas escribimos el siguiente programa:

#include <ESP8266WiFi.h>
void setup() {
Serial.begin(115200); Serial.println();Serial.println();
Serial.print("AP MAC: "); Serial.println(WiFi.softAPmacAddress()); // MAC como AP
Serial.print("STA MAC: "); Serial.println(WiFi.macAddress()); // MAC como estacion-station
}
void loop() {}
En mi caso, salen estos resultados:

Master

AP MAC: EE:FA:BC:C5:AC:AF
STA MAC: EC:FA:BC:C5:AC:AF

Slave

AP MAC: A6:CF:12:DF:5A:6B
STA MAC: A4:CF:12:DF:5A:6B


Tal como dicen en la web de Dani No,

La dirección MAC que debemos asignar a un par, depende de la conexión WiFi que tenga establecida y su papel en el par de comunicación. En la siguiente tabla se resumen las posibles combinaciones y la MAC a elegir:

TIPO DE CONEXIÓN WiFi
SIN CONEXIÓN AP STA AP+STA
PAPEL MAESTRO STA MAC AP MAC STA MAC* AP MAC
ESCLAVO STA MAC AP MAC* STA MAC STA MAC*

*Conexiones WiFi sugeridas por Spressif, en el caso de que se utilicen. (Maestro-STA y Esclavo-AP o AP+STA)

¿Cómo se establece una comunicación? En la web se nos hace un resumen de las funciones a incorporar, divididas en grupos. Podemos verlas mejor en ella. Simplemente me refiero ahora con el esquema:



Ejemplo

Circuito esclavo Circuito Maestro


Script del maestro


/*
Ejemplo de comunicación ESP-NOW por Dani No www.esploradores.com
***ESTE SKETCH CORRESPONDE AL PAR MAESTRO***
El sketch permite el envío de dos datos mediante la comunicación ESP-NOW a un par esclavo:
- En la variable -potenciometro- se envía el dato de la lectura de la entrada
analógica del ESP. Se leen y envían -valores entre 0 y 1023- que se hacen variar
mediante un potenciómetro y se utilizarán para regular la intensidad del LED conectado
en el circuito esclavo.
- En la variable -tiempo- se envía el dato del milisegundo en el que el que se envían
los datos al circuito esclavo.
¡¡¡IMPORTANTE!!!
Para hacer funcionar la comunicación ESP-NOW si se tiene instalado en Arduino como gestor
de tarjetas el: esp8266 by ESP8266 Community versión 2.3.0 (Se puede comprobar buscándolo en:
Herramientas->Placa:"NodeMCU 1.0(ESP-12E Module)"->Gestor de tarjetas..., es necesario editar
el fichero: ~/Library/Arduino15/packages/esp8266/hardware/esp8266/2.1.0/platform.txt,
buscar "compiler.c.elf.libs", y añadir al final de la línea "-lespnow".
*/
#include <ESP8266WiFi.h>
extern "C" {
#include <espnow.h>
}
//***ESTRUCTURA DE LOS DATOS TRANSMITIDOS MAESTRO/ESCLAVO***//
//Se de establecer IGUAL en el par esclavo
struct ESTRUCTURA_DATOS {
uint16_t potenciometro;
uint32_t tiempo;
};
void setup() {
//***INICIALIZACIÓN DEL PUERTO SERIE***//
Serial.begin(115200); Serial.println();Serial.println();
//***INICIALIZACIÓN DEL PROTOCOLO ESP-NOW***//
if (esp_now_init()!=0) {
Serial.println("*** ESP_Now init failed");
ESP.restart();
delay(1);
}
//***DATOS DE LAS MAC (Access Point y Station) del ESP***//
Serial.print("Access Point MAC de este ESP: "); Serial.println(WiFi.softAPmacAddress());
Serial.print("Station MAC de este ESP: "); Serial.println(WiFi.macAddress());
//***DECLARACIÓN DEL PAPEL DEL DISPOSITIVO ESP EN LA COMUNICACIÓN***//
//0=OCIOSO, 1=MAESTRO, 2=ESCLAVO y 3=MAESTRO+ESCLAVO
esp_now_set_self_role(1);
//***EMPAREJAMIENTO CON EL ESCLAVO***//
// Dirección MAC del ESP con el que se empareja (esclavo)
// Se debe introducir la STA MAC correspondiente
uint8_t mac_addr[6] = {0xA4, 0xCF, 0x12, 0xDF, 0x5A, 0x6B}; // STA MAC esclavo
uint8_t role=2;
uint8_t channel=3;
uint8_t key[0]={}; //no hay clave
//uint8_t key[16] = {0,255,1,1,1,1,1,1,1,1,1,1,1,1,1,1};
uint8_t key_len=sizeof(key);
Serial.print("Tamaño de *key: "); Serial.println(key_len);
esp_now_add_peer(mac_addr,role,channel,key,key_len);
}
void loop() {
//***DATOS A ENVIAR***//
ESTRUCTURA_DATOS ED;
ED.potenciometro = analogRead(A0);
Serial.print("Dato potenciometro: "); Serial.print(ED.potenciometro);
delay(20);
ED.tiempo = millis();
Serial.print(". Dato tiempo: "); Serial.print(ED.tiempo);
//***ENVÍO DE LOS DATOS***//
//uint8_t *da=NULL; //NULL envía los datos a todos los ESP con los que está emparejado
uint8_t da[6] = {0xA4, 0xCF, 0x12, 0xDF, 0x5A, 0x6B}; // ¿mismos datos que STA MAC?
uint8_t data[sizeof(ED)]; memcpy(data, &ED, sizeof(ED));
uint8_t len = sizeof(data);
esp_now_send(da, data, len);
delay(1); //Si se pierden datos en la recepción se debe subir este valor
//***VERIFICACIÓN DE LA RECEPCIÓN CORRECTA DE LOS DATOS POR EL ESCLAVO***//
esp_now_register_send_cb([](uint8_t* mac, uint8_t status) {
char MACesclavo[6];
sprintf(MACesclavo,"%02X:%02X:%02X:%02X:%02X:%02X",mac[0],mac[1],mac[2],mac[3],mac[4],mac[5]);
Serial.print(". Enviado a ESP MAC: "); Serial.print(MACesclavo);
Serial.print(". Recepcion (0=0K - 1=ERROR): "); Serial.println(status);
});
}


Script del esclavo


/*
Ejemplo de comunicación ESP-NOW por Dani No www.esploradores.com
***ESTE SKETCH CORRESPONDE AL PAR ESCLAVO***
El sketch permite la recepción de una comunicación vía ESP-NOW de dos datos enviados
por el par maestro.
- En la variable -potenciometro- se envía el dato de la lectura de la entrada
analógica del circuito maestro -valores entre 0 y 1023-, que se utilizarán
para regular la intensidad del LED conectado en el circuito esclavo.
- En la variable -tiempo- se envía el dato del milisegundo en el que el circuito maestro
realiza la comunicación con el circuito esclavo.
¡¡¡IMPORTANTE!!!
Para hacer funcionar la comunicación ESP-NOW si se tiene instalado en Arduino como gestor
de tarjetas el: esp8266 by ESP8266 Community versión 2.3.0 (Se puede comprobar buscándolo en:
Herramientas->Placa:"NodeMCU 1.0(ESP-12E Module)"->Gestor de tarjetas..., es necesario editar
el fichero: ~/Library/Arduino15/packages/esp8266/hardware/esp8266/2.1.0/platform.txt,
buscar "compiler.c.elf.libs", y añadir al final de la línea "-lespnow".
*/
#include <ESP8266WiFi.h>
extern "C" {
#include <espnow.h>
}
//***ESTRUCTURA DE LOS DATOS TRANSMITIDOS MAESTRO/ESCLAVO***//
//Se de establecer IGUAL en el par maestro
struct ESTRUCTURA_DATOS {
uint16_t potenciometro = 0;
uint32_t tiempo = 0;
};
//***PIN de conexión del LED a regular con el potenciometro del ESP MAESTRO***//
int PinLED = 5; //Pin D1
void setup() {
//***INICIALIZACIÓN DEL PUERTO SERIE***//
Serial.begin(115200); Serial.println();
//***INICIALIZACIÓN DEL PROTOCOLO ESP-NOW***//
if (esp_now_init()!=0) {
Serial.println("Protocolo ESP-NOW no inicializado...");
ESP.restart();
delay(1);
}
//***DATOS DE LAS MAC (Access Point y Station) del ESP***//
Serial.print("AP MAC: "); Serial.println(WiFi.softAPmacAddress());
Serial.print("STA MAC: "); Serial.println(WiFi.macAddress());
//***DECLARACIÓN DEL PAPEL DEL DISPOSITIVO ESP EN LA COMUNICACIÓN***//
//0=OCIOSO, 1=MAESTRO, 2=ESCLAVO y 3=MAESTRO+ESCLAVO
esp_now_set_self_role(2);
//***DECLARACIÓN del PinLED como SALIDA***//
pinMode(PinLED, OUTPUT);
}
void loop() {
//***RECEPCIÓN DE LA COMUNICACIÓN ESP-NOW***//
esp_now_register_recv_cb([](uint8_t *mac, uint8_t *data, uint8_t len) {
char MACmaestro[6];
sprintf(MACmaestro, "%02X:%02X:%02X:%02X:%02X:%02X",mac[0],mac[1],mac[2],mac[3],mac[4],mac[5]);
Serial.print("Recepcion desde ESP MAC: "); Serial.print(MACmaestro);
ESTRUCTURA_DATOS ED;
memcpy(&ED, data, sizeof(ED));
Serial.print(". Dato potenciometro: "); Serial.print(ED.potenciometro);
Serial.print(". Dato tiempo: "); Serial.println(ED.tiempo);
analogWrite(PinLED,ED.potenciometro);
});
}




= = = = = = = = = 
Bibliografía
=========

https://www.esploradores.com/practica-6-conexion-esp-now/
https://randomnerdtutorials.com/esp-now-two-way-communication-esp32/


19 de marzo de 2020

NodeMCU: 06_Conectamos nuestro NodeMCU como station a nuestro router de casa (AP)

En este caso, nuestro NodeMCU está conectado a un LED como en el anterior. Las conexiones son las mismas.

Por otra parte, ahora necesito la SSID y la contraseña de nuestro router inalámbrico. Ese será nuestro punto de acceso. Una vez conectados, nuestro NodeMCU como cliente estará a la espera de una petición.

Esa petición proviene del navegador de otro dispositivo, como nuestro móvil o nuestro ordenador. En él, escribiremos la IP del NodeMCU al que nos hemos conectado. La IP aparece en el monitor Serie al resetear nuestro NodeMCU.

Se han añadido al programa original una línea para poder escribir acentos (codificación UTF-8) y las etiquetas body.

Además, si abrimos el puerto 80 en nuestro router y hacemos una redirección de las peticiones por este puerto a la IP de nuestro NodeMCU, podremos controlarlo desde el exterior. Se explica para un router determinado en el segundo enlace de la bibliografía.

/*
NodeMCU Server - Conexión en modo Station con un punto de acceso (router) por Dani No www.esploradores.es
Crea una conexión del NodeMCU en modo Station con un punto de acceso que permite
encender y apagar un LED conectado a la salida D4 (GPIO02) del módulo NodeMCU.
Este código de ejemplo es de público dominio.
Modificado por Aurelio Gallardo
*/
#include <ESP8266WiFi.h> //Incluye la librería ESP8266WiFi
const char* ssid = "JAZZTEL_XXXX"; //Indicamos el nombre de la red WiFi (SSID) a la que queremos conectarnos.
const char* password = "xxxxxxxxxxxxx"; //Indicamos la contraseña de de red WiFi
WiFiServer server(80); //Definimos el puerto de comunicaciones
int PinLED = D1; // GPI05 //Definimos el pin de salida - GPI05 / D4
int estado = LOW; //Definimos la variable que va a recoger el estado del LED
void setup() {
Serial.begin(115200);
pinMode(PinLED, OUTPUT); //Inicializamos el GPI05 como salida
digitalWrite(PinLED, LOW); //Dejamos inicialmente el GPI05 apagado
WiFi.begin(ssid, password); //Inicializamos la conexión del NodeMCU con la red WiFi
Serial.printf("\n\nConectando a la red: %s\n", WiFi.SSID().c_str());
while (WiFi.status() != WL_CONNECTED) { // Verifica el estado de la conexión del NodeMCU cada 0,5s hasta que conecta
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi conectada"); // Indica que el NodeMCU conectado con la red WiFi
server.begin(); // Inicia el NodeMCU en modo Station
Serial.println("Servidor inicializado");
Serial.printf("IP local del NodeMCU: %s\n", WiFi.localIP().toString().c_str());
Serial.printf("DNS #1, #2 IP: %s, %s\n", WiFi.dnsIP().toString().c_str(), WiFi.dnsIP(1).toString().c_str());
Serial.printf("Submascara de red -subnetMask-: %s\n", WiFi.subnetMask().toString().c_str());
Serial.printf("Direccion MAC en modo Server -macAddress-: %s\n", WiFi.macAddress().c_str());
Serial.printf("IP privada del punto de acceso -dnsIP-: %s\n", WiFi.gatewayIP().toString().c_str());
Serial.printf("Nombre del NodeMCU como cliente -hostname-: %s\n", WiFi.hostname().c_str());
Serial.printf("Connection status: %d\n0=WL_IDLE_STATUS, 1=WL_NO_SSID_AVAIL, 3=WL_CONNECTED, 4=WL_CONNECTED-FAILED y 6=WL_DISCONNECTED\n", WiFi.status());
Serial.printf("Nombre de red -SSID-: %s\n", WiFi.SSID().c_str());
Serial.printf("Clave de red -Password-: %s\n", WiFi.psk().c_str());
Serial.printf("Direccion MAC del punto de acceso -BSSID-: %s\n", WiFi.BSSIDstr().c_str());
Serial.printf("Intensidad de la conexion con el punto de acceso -RSSI-: %d dB\n", WiFi.RSSI());
Serial.printf("\n\nUtiliza esta URL para conectar: http://%s/\n", WiFi.localIP().toString().c_str());
}
void loop()
{
// Comprueba si el cliente ha conectado
WiFiClient client = server.available();
if (!client) {
return;
}
// Espera hasta que el cliente envía alguna petición
Serial.println("nuevo cliente");
while(!client.available()){
delay(1);
}
// Lee la petición
String peticion = client.readStringUntil('\r');
Serial.println(peticion);
client.flush(); // Descarga los bytes enviados al cliente pero todavía no leidos
// Comprueba la petición
if (peticion.indexOf('/LED=ON') != -1) {
estado = HIGH;
}
if (peticion.indexOf('/LED=OFF') != -1){
estado = LOW;
}
//Enciende o apaga el LED en función de la petición
digitalWrite(PinLED, estado);
// Envía la página HTML de respuesta al cliente
client.println("HTTP/1.1 200 OK");
client.println(""); //No olvidar esta línea de separación
client.println("");
client.println("");
client.println("<head><meta charset='UTF-8'></head>"); //Añado la línea para codificación de caracteres.
// Así podemos leer los acentos
client.print("<body>"); // Incluyo etiqueta body
client.print("<h1 align=center>El LED está ahora: ");
if(estado == HIGH) {
client.print("ENCENDIDO</h1>");
client.print("<img src='https://esploradores.com/Practicas_html/LED_encendido.png' alt='Bombilla encendida' style='display:block; margin:auto' width='150px'>");
client.print("<input type='image' src='https://esploradores.com/Practicas_html/apagar_300x88.png' style='display:block; margin:auto' width='250px' onClick=location.href='/LED=OFF'>");
} else {
client.print("APAGADO</h1>");
client.print("<img src='https://esploradores.com/Practicas_html/LED_apagado.png' alt='Bombilla apagada' style='display:block; margin:auto' width='150px'>");
client.print("<input type='image' src='https://esploradores.com/Practicas_html/encender_300x88.png' style='display:block; margin:auto' width='250px' onClick=location.href='/LED=ON'>");
}
client.println("</body>"); // Incluyo etiqueta fin de body
client.println("</html>");
delay(1);
Serial.println("Peticion finalizada"); // Se finaliza la petición al cliente. Se inicializa la espera de una nueva petición.
Serial.println("");
}


Bibliografía
========

https://www.esploradores.com/practica-3-station-conexion-con-access-point/
https://www.esploradores.com/practica-4-station-conexion-desde-cualquier-sitio-del-mundo-con-access-point-encendido-y-apagado-de-un-led/


18 de marzo de 2020

NodeMCU: 05_Punto de acceso_y_web_server.


El código que convierte el NodeMCU en punto de acceso es el siguiente:

#include <ESP8266WiFi.h> // Incluye la biblioteca Wifi
const char *ssid = "Probando"; // Nombre de la red que emito
const char *password = "Probando"; // Contraseña para conectarse
void setup() {
Serial.begin(115200);
delay(10);
Serial.println('\n');
WiFi.softAP(ssid, password); // Emitiendo como Punto de acceso
Serial.print("Access Point \"");
Serial.print(ssid);
Serial.println("\" started");
Serial.print("IP address:\t");
Serial.println(WiFi.softAPIP()); // Desde qué IP emito
}
void loop() { }

En el programa, lo importante es la orden WiFi.softAP(ssid, password);   ue convierte nuestro NodeMCU en un punto de acceso.

= = = = = = = = = = 

En el siguiente programa, profundizamos en este concepto. No sólo convierto nuestro NodeMCU en punto de acceso sino que a través de un puerto emite contenido en HTML. Este contenido puede ser captado desde un navegador en un móvil, por ejemplo, y ser usado para mandar información de vuelta al AP, pudiendo cambiar un estado.

En el siguiente ejemplo, modificación del ejemplo que se cita en la bibliografía de la web https://www.esploradores.com/, puede actuarse desde el navegador encendiendo u apagando un LED.



/*
NodeMCU Access Point - Servidor Web por Dani No www.esploradores.com
Crea un servidor Web en modo Access Point que permite encender y apagar un LED conectado a la salida D4 (GPIO02) del módulo NodeMCU.
Este código de ejemplo es de público dominio.
*/
#include <ESP8266WiFi.h> //Incluye la librería ESP8266WiFi
const char ssid[] = "DeAurelio"; //Definimos la SSDI de nuestro servidor WiFi -nombre de red-
const char password[] = "12345678"; //Definimos la contraseña de nuestro servidor
WiFiServer server(80); //Definimos el puerto de comunicaciones
int PinLED = D1; //Definimos el pin de salida - GPIO2 / D1
int estado = LOW; //Definimos la variable que va a recoger el estado del LED
void setup() {
Serial.begin(115200);
pinMode(PinLED, OUTPUT); //Inicializamos el GPIO2 como salida
digitalWrite(PinLED, LOW); //Dejamos inicialmente el GPIO2 apagado
server.begin(); //inicializamos el servidor
WiFi.mode(WIFI_AP);
WiFi.softAP(ssid, password); //Red con clave, en el canal 1 y visible
//WiFi.softAP(ssid, password,3,1); //Red con clave, en el canal 3 y visible
//WiFi.softAP(ssid); //Red abierta
Serial.println();
Serial.print("Direccion IP Access Point - por defecto: "); //Imprime la dirección IP
Serial.println(WiFi.softAPIP());
Serial.print("Direccion MAC Access Point: "); //Imprime la dirección MAC
Serial.println(WiFi.softAPmacAddress());
//IPAddress local_ip(192, 168, 1, 1); //Modifica la dirección IP
//IPAddress gateway(192, 168, 1, 1);
//IPAddress subnet(255, 255, 255, 0);
//WiFi.softAPConfig(local_ip, gateway, subnet);
//Serial.println();
//Serial.print("Access Point - Nueva direccion IP: ");
//Serial.println(WiFi.softAPIP());
}
void loop()
{
// Comprueba si el cliente ha conectado
WiFiClient client = server.available();
if (!client) {
return;
}
// Espera hasta que el cliente envía alguna petición
Serial.println("nuevo cliente");
while(!client.available()){
delay(1);
}
// Imprime el número de clientes conectados
Serial.printf("Clientes conectados al Access Point: %d", WiFi.softAPgetStationNum());
// Lee la petición
String peticion = client.readStringUntil('r');
Serial.println(peticion);
client.flush();
// Comprueba la petición
if (peticion.indexOf('/LED=ON') != -1) {
estado = HIGH;
}
if (peticion.indexOf('/LED=OFF') != -1){
estado = LOW;
}
//Enciende o apaga el LED en función de la petición
digitalWrite(PinLED, estado);
// Envía la página HTML de respuesta al cliente
client.println("HTTP/1.1 200 OK");
client.println(""); //No olvidar esta línea de separación
client.println("<!DOCTYPE HTML>");
client.println("<meta charset='UTF-8'>");
client.println("<html>");
//Imprime el estado del led
client.print("<h1>El LED está ahora: ");
if(estado == HIGH) {
client.print("ENCENDIDO</h1>");
} else {
client.print("APAGADO</h1>");
}
//Se crean enlaces para modificar el estado del LED
client.println("Presiona <a href='/LED=ON'>AQUÍ</a> para encender el LED<br>");
client.println("Presiona <a href='/LED=OFF'>AQUÍ</a> para apagar el LED<br><br>");
//Se crean cajas de comprobación (checkbox) para modificar el estado del LED
client.println("<input type='checkbox' onClick=location.href='/LED=ON'> ENCENDER </input><br>");
client.println("<input type='checkbox' onClick=location.href='/LED=OFF'> APAGAR </input><br><br>");
//Se crean botones para modificar el estado del LED
client.println("<button type='button' onClick=location.href='/LED=ON'> ENCENDER </button>");
client.println("<button type='button' onClick=location.href='/LED=OFF'> APAGAR </button><br><br>");
//Se crean botones con estilos para modificar el estado del LED
client.println("<button type='button' onClick=location.href='/LED=ON' style='margin:auto; background-color:green; color:#A9F5A9; padding:5px; border:2px solid black; width:200;'><h2> ENCENDER</h2> </button>");
client.println("<button type='button' onClick=location.href='/LED=OFF' style='margin:auto; background-color:red; color:#F6D8CE; padding:5px; border:2px solid black; width:200;'><h2> APAGAR</h2> </button><br><br>");
//Se crea un único botón para modificar el estado del LED
if(estado == HIGH) {
client.print("<button type='button' onClick=location.href='/LED=OFF'> APAGAR </button><br><br>");
} else {
client.print("<button type='button' onClick=location.href='/LED=ON'> ENCENDER </button><br><br>");
}
client.println("</html>");
delay(1);
Serial.println("Petición finalizada"); // Se finaliza la petición al cliente. Se inicaliza la espera de una nueva petición.
//Desconexión de los clientes
//WiFi.softAPdisconnect();
}
.

Bibliografía
=========
https://www.esploradores.com/access-point-servidor-web-nodemcu/

https://tttapa.github.io/ESP8266/Chap01%20-%20ESP8266.html

16 de marzo de 2020

NodeMCU: 03_ESPNOW (Emisor y receptor - primeras pruebas)

Receptor

/*
Rui Santos
Complete project details at https://RandomNerdTutorials.com/esp-now-esp8266-nodemcu-arduino-ide/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files.
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
Modificado por Aurelio gallardo
*/
#include <ESP8266WiFi.h>
#include <espnow.h>
// Ejemplo de estructura de enviar datos
// debe coincidir la estructura del receptor
typedef struct struct_message {
char a[32];
int b;
float c;
String d;
bool e;
} struct_message;
// Crear un mensaje estructurado llamado myData
struct_message myData;
// Función callback se ejecutará cuando se reciban datos
void OnDataRecv(uint8_t * mac, uint8_t *incomingData, uint8_t len) {
memcpy(&myData, incomingData, sizeof(myData));
Serial.print("Bytes received: ");
Serial.println(len);
Serial.print("Char: ");
Serial.println(myData.a);
Serial.print("Int: ");
Serial.println(myData.b);
Serial.print("Float: ");
Serial.println(myData.c);
Serial.print("String: ");
Serial.println(myData.d);
Serial.print("Bool: ");
Serial.println(myData.e);
Serial.println();
}
void setup() {
// Inicializa el monitor serie
Serial.begin(115200);
// Establece el dispositivo como estación WIFI
WiFi.mode(WIFI_STA);
// Iniciar ESP-NOW
if (esp_now_init() != 0) {
Serial.println("Error inicializando ESP-NOW");
return;
}
// Una vez ESPNow se inicializa con éxito, usaremos recv CB para
// obtener la información del paquete recibido
esp_now_set_self_role(ESP_NOW_ROLE_SLAVE); // Ahora este es el esclavo
esp_now_register_recv_cb(OnDataRecv); // función callback
}
void loop() {
}


===============

Emisor

/*
Rui Santos
Complete project details at https://RandomNerdTutorials.com/esp-now-esp8266-nodemcu-arduino-ide/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files.
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
Modificado por Aurelio Gallardo.
*/
#include <ESP8266WiFi.h>
#include <espnow.h> // Biblioteca ESPNOW
// Esta es la dirección del ue va A RECIBIR los datos
uint8_t broadcastAddress[] = {0xA4, 0xCF, 0x12, 0xDF, 0x5A, 0x6B};
// Ejemplo de estructura de enviar datos
// debe coincidir la estructura del receptor
typedef struct struct_message {
char a[32];
int b;
float c;
String d;
bool e;
} struct_message;
// Crear un mensaje estructurado llamado myData
struct_message myData;
// Función callback cuando datos se envían
void OnDataSent(uint8_t *mac_addr, uint8_t sendStatus) {
Serial.print("Status del último paquete enviado: ");
if (sendStatus == 0){
Serial.println("Entregado con éxito");
}
else{
Serial.println("Entrega fallida");
}
}
void setup() {
// Inicializa monitor serie
Serial.begin(115200);
// Set device as a Wi-Fi Station
WiFi.mode(WIFI_STA);
// Init ESP-NOW
if (esp_now_init() != 0) {
Serial.println("Error inicializando ESP-NOW");
return;
}
// Once ESPNow is successfully Init, we will register for Send CB to
// get the status of Trasnmitted packet
// Una vez que ESPNOW se inicializa con éxito, usaremos Send CB
// para obtener el estado del paquete transmitido.
esp_now_set_self_role(ESP_NOW_ROLE_CONTROLLER); // como controlador
esp_now_register_send_cb(OnDataSent); // define la función de callback
// Registra pareja
// La función esp_now_add_peer acepta los argumentos (en orden):
// mac address, role, wi-fi channel, key, and key length.
esp_now_add_peer(broadcastAddress, ESP_NOW_ROLE_SLAVE, 1, NULL, 0);
}
void loop() {
// Set values to send
strcpy(myData.a, "THIS IS A CHAR");
myData.b = random(1,20);
myData.c = 1.2;
myData.d = "Hello";
myData.e = false;
// Envía el mensaje via ESP-NOW
esp_now_send(broadcastAddress, (uint8_t *) &myData, sizeof(myData));
delay(500);
}

Al principio pensé que no funcionaban los programas. Pero algo me hizo sospechar de una unidad... Así era. Ambos programas funcionan perfectamente.

NodeMCU: 02_ ESPNOW (Comunicación punto a punto // funciones usadas )

Pretendo hacer lo siguiente:
  1.  Un módulo ESP8266 actuará como emisor y el otro como receptor
  2.  Mandaremos una estructura de datos, que puede contener variables de tipo char, int, float, String, boolean. Se podrá modificar para enviar otra estructura de datos.
  3. ESPNOW trabaja con funciones callback (de retorno) que serán llamadas cuando se produce un evento: se recibe o se envía un mensaje, o se produce un error en el envío.
  4. Respecto al emisor:
    1.  Se inicializa ESP-NOW
    2. Se creará una función callback (OnDataSent) que se ejecutará al enviar un mensaje, y así sabremos si el mensaje se ha enviado con éxito o no.
    3. Añadiremos un receptor a través de su dirección MAC.
    4. Enviaremos el mensaje a este receptor
  5. Respecto al receptor:
    1.  Se inicializa ESP-NOW
    2.  Se creará una función callback (OnDataRecv) que se ejecutará cuando se reciba un mensaje.
    3. Dentro de esa función, se almacenará una variable con el valor del mensaje, y se podrá realizar cualquier tarea con dicha información.
==============

Las funciones que usa el protocolo son:

  1. esp_now_init() --> Inicializa ESP-NOW. hay que inicializar Wi-Fi antes. Si tiene exito, retorna 0.
  2. esp_now_set_self_role(role) --> establece perfil; puede ser. ESP_NOW_ROLE_IDLE = 0,
    ESP_NOW_ROLE_CONTROLLER, ESP_NOW_ROLE_SLAVE, ESP_NOW_ROLE_COMBO, ESP_NOW_ROLE_MAX
  3. esp_now_add_peer (uint8 mac_addr, uint8 role, uint8 channel, uint8 key, uint8 key_len) --> llamar a esta función para emparejarse a otro nodeMCU
  4. esp_now_register_send_cb() --> registra una función callback que se dispara tras enviar datos, y devuelve si la entrega tuvo éxito o no.
  5. esp_now_register_rcv_cb() --> registra una función callback que se dispara tras recibir datos via ESP-NOW.

Más información en: 








NodeMCU: 01_ ESPNOW (Averiguar MAC)

En primer lugar, en enlace que contiene la guía que voy a seguir se encuentra en:

https://randomnerdtutorials.com/esp-now-esp8266-nodemcu-arduino-ide/

https://randomnerdtutorials.com/projects-esp8266/

Y, punto por punto:
  1. No instalo el gestor de tarjetas porque ya lo tenía instalado. De todas formas, la guía para hacerlo (https://randomnerdtutorials.com/how-to-install-esp8266-board-arduino-ide/) aparece en la web. 
  2. Cargo el siguiente programa para averiguar las MACs. Los "NodeMCU" se llevan mal con el puerto serie en el setup. Probablemente tendrás que pulsar RESET para que aparezca la información en la pantalla.
  3. #include <ESP8266WiFi.h>
    void setup(){
    Serial.begin(115200);
    Serial.println();
    Serial.print("ESP8266 Board MAC Address: ");
    Serial.println(WiFi.macAddress());
    }
    void loop(){
    }
  4. La salida del puerto serie es algo como lo que sigue: "ESP8266 Board MAC Address:  DC:4F:11:22:AA:CC " (la MAC es inventada). Apunta la MAC.

============================================
BIBLIOGRAFÍA
============================================
https://hackaday.io/project/164132-hello-world-for-esp-now
https://www.fernandok.com/2018/03/esp32-com-protocolo-esp-now.html

https://www.instructables.com/id/ESP32-With-ESP-Now-Protocol/
https://espressif.com/sites/default/files/documentation/esp-now_user_guide_en.pdf

http://www.esploradores.com/practica-6-conexion-esp-now/

 https://youtu.be/6NsBN42B80Q

 Parece que no hay que instalar la librería espnow.h, solo llamarla ¿¿??

15 de marzo de 2020

Recopilación de programas gratuitos que sirven para hacer videotutoriales


RecordMyDesktop: grabación de Escritorio (muy bueno). Sistemas Linux. Instalación nueva en http://ubuntuhandbook.org/index.php/2020/01/install-vokoscreenng-3-0-ppa-ubuntu-18-04-19-10/

VokoScreen: grabación de Escritorio con posibilidad de grabar la entrada de la videocámara (bueno). Sistemas Linux y Windows (no lo he testeado en Windows).

Screen Cast: app de móviles que permite lanzar lo que se ve por la pantalla a la red. Se visualiza en el ordenador que esté grabando con los programas anteriores.

Edición de vídeo en Ubuntu: Kdenlive (muy bueno), Openshot (más simple - también disponible en Windows aunque no lo he usado con él).