sábado, 14 de octubre de 2017

Tutorial #22 ESP8266 – WebSocket Server / Led RGB

En este tutorial explico cómo montar un servidor web que soporta WebSockets en un ESP8266 y muestro como utilizar dicho servidor web para controlar un led RGB. La aplicación de WebSockets en IOT (internet de las cosas) nos permite crear dispositivos con una excelente experiencia de usuario, ya que el uso de WebSockets es una de las tecnologías web con menor latencia.


Lista de Materiales:

1) NodeMCU (ESP8266)
1) Led RGB (ánodo común)
3) Resistencia de 330 ohms.


WebSocketServer_STA:

#include <ESP8266WiFi.h>
#include <WebSocketsServer.h>
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>

#define LED_RED     05 // D1
#define LED_GREEN   12 // D6
#define LED_BLUE    13 // D7

const char* ssid = "-----";
const char* password = "-----";
int contconexion = 0;

String pagina ="<html>"
"<head>"
"<script>"
"var connection = new WebSocket('ws://'+location.hostname+':81/', ['arduino']);"
"connection.onopen = function ()       { connection.send('Connect ' + new Date()); };"
"connection.onerror = function (error) { console.log('WebSocket Error ', error);};"
"connection.onmessage = function (e)   { console.log('Server: ', e.data);};"
"function sendRGB() {"
" var r = parseInt(document.getElementById('r').value).toString(16);"
" var g = parseInt(document.getElementById('g').value).toString(16);"
" var b = parseInt(document.getElementById('b').value).toString(16);"
" if(r.length < 2) { r = '0' + r; }"
" if(g.length < 2) { g = '0' + g; }"
" if(b.length < 2) { b = '0' + b; }"
" var rgb = '#'+r+g+b;"
" console.log('RGB: ' + rgb);"
" connection.send(rgb);"
"}"
"</script>"
"</head>"
"<body>"
"LED Control:<br/><br/>"
"R: <input id='r' type='range' min='0' max='255' step='1' value='0' oninput='sendRGB();'/><br/>"
"G: <input id='g' type='range' min='0' max='255' step='1' value='0' oninput='sendRGB();'/><br/>"
"B: <input id='b' type='range' min='0' max='255' step='1' value='0'oninput='sendRGB();'/><br/>"
"</body>"
"</html>";

ESP8266WebServer server = ESP8266WebServer(80);
WebSocketsServer webSocket = WebSocketsServer(81);

void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length) {

    switch(type) {
        case WStype_DISCONNECTED:
            Serial.printf("[%u] Disconnected!\n", num);
            break;
        case WStype_CONNECTED: {
            IPAddress ip = webSocket.remoteIP(num);
            Serial.printf("[%u] Connected from %d.%d.%d.%d url: %s\n", num, ip[0], ip[1], ip[2], ip[3], payload);

            // send message to client
            webSocket.sendTXT(num, "Connected");
        }
            break;
        case WStype_TEXT:
            Serial.printf("[%u] get Text: %s\n", num, payload);

            if(payload[0] == '#') {
                // we get RGB data

                // decode rgb data
                uint32_t rgb = (uint32_t) strtol((const char *) &payload[1], NULL, 16);

                analogWrite(LED_RED,    abs(255 - (rgb >> 16) & 0xFF) );
                analogWrite(LED_GREEN,  abs(255 - (rgb >>  8) & 0xFF) );
                analogWrite(LED_BLUE,   abs(255 - (rgb >>  0) & 0xFF) );
            }
            break;
    }
}

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

  WiFi.mode(WIFI_STA); //para que no inicie el SoftAP en el modo normal
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED and contconexion <50) { //Cuenta hasta 50 si no se puede conectar lo cancela
    ++contconexion;
    delay(500);
    Serial.print(".");
  }
  if (contconexion <50) {
      //para usar con ip fija
      IPAddress Ip(192,168,1,180); 
      IPAddress Gateway(192,168,1,1); 
      IPAddress Subnet(255,255,255,0); 
      WiFi.config(Ip, Gateway, Subnet); 
      
      Serial.println("");
      Serial.println("WiFi conectado");
      Serial.println(WiFi.localIP());
  }
  else { 
      Serial.println("");
      Serial.println("Error de conexion");
  }

  pinMode(LED_RED, OUTPUT);
  pinMode(LED_GREEN, OUTPUT);
  pinMode(LED_BLUE, OUTPUT);

  // start webSocket server
  webSocket.begin();
  webSocket.onEvent(webSocketEvent);

  if(MDNS.begin("esp8266")) {
    Serial.println("MDNS responder started");
  }

  // handle index
  server.on("/", []() {
      server.send(200, "text/html", pagina);
  });

  server.begin();

  // Add service to MDNS
  MDNS.addService("http", "tcp", 80);
  MDNS.addService("ws", "tcp", 81);

  digitalWrite(LED_RED,   1); // 1 = apagado
  digitalWrite(LED_GREEN, 1);
  digitalWrite(LED_BLUE,  1);

  analogWriteRange(255);

}

void loop() {
    webSocket.loop();
    server.handleClient();
}


WebSocketServer_softAP:

#include <ESP8266WiFi.h>
#include <WebSocketsServer.h>
#include <ESP8266WebServer.h>

#define LED_RED     05 // D1
#define LED_GREEN   12 // D6
#define LED_BLUE    13 // D7

const char* ssid = "RGB";
const char* password = "asdfghjk";

String pagina ="<html>"
"<head>"
"<script>"
"var connection = new WebSocket('ws://'+location.hostname+':81/', ['arduino']);"
"connection.onopen = function ()       { connection.send('Connect ' + new Date()); };"
"connection.onerror = function (error) { console.log('WebSocket Error ', error);};"
"connection.onmessage = function (e)   { console.log('Server: ', e.data);};"
"function sendRGB() {"
" var r = parseInt(document.getElementById('r').value).toString(16);"
" var g = parseInt(document.getElementById('g').value).toString(16);"
" var b = parseInt(document.getElementById('b').value).toString(16);"
" if(r.length < 2) { r = '0' + r; }"
" if(g.length < 2) { g = '0' + g; }"
" if(b.length < 2) { b = '0' + b; }"
" var rgb = '#'+r+g+b;"
" console.log('RGB: ' + rgb);"
" connection.send(rgb);"
"}"
"</script>"
"</head>"
"<body>"
"LED Control:<br/><br/>"
"R: <input id='r' type='range' min='0' max='255' step='1' value='0' oninput='sendRGB();'/><br/>"
"G: <input id='g' type='range' min='0' max='255' step='1' value='0' oninput='sendRGB();'/><br/>"
"B: <input id='b' type='range' min='0' max='255' step='1' value='0'oninput='sendRGB();'/><br/>"
"</body>"
"</html>";

ESP8266WebServer server = ESP8266WebServer(80);
WebSocketsServer webSocket = WebSocketsServer(81);

void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length) {

    switch(type) {
        case WStype_DISCONNECTED:
            Serial.printf("[%u] Disconnected!\n", num);
            break;
        case WStype_CONNECTED: {
            IPAddress ip = webSocket.remoteIP(num);
            Serial.printf("[%u] Connected from %d.%d.%d.%d url: %s\n", num, ip[0], ip[1], ip[2], ip[3], payload);

            // send message to client
            webSocket.sendTXT(num, "Connected");
        }
            break;
        case WStype_TEXT:
            Serial.printf("[%u] get Text: %s\n", num, payload);

            if(payload[0] == '#') {
                // we get RGB data

                // decode rgb data
                uint32_t rgb = (uint32_t) strtol((const char *) &payload[1], NULL, 16);

                analogWrite(LED_RED,    abs(255 - (rgb >> 16) & 0xFF) );
                analogWrite(LED_GREEN,  abs(255 - (rgb >>  8) & 0xFF) );
                analogWrite(LED_BLUE,   abs(255 - (rgb >>  0) & 0xFF) );
            }
            break;
    }
}

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

  WiFi.softAP(ssid, password);
  IPAddress myIP = WiFi.softAPIP(); 
  Serial.print("IP del access point: ");
  Serial.println(myIP);
  Serial.println("WebServer iniciado...");

  pinMode(LED_RED, OUTPUT);
  pinMode(LED_GREEN, OUTPUT);
  pinMode(LED_BLUE, OUTPUT);

  // start webSocket server
  webSocket.begin();
  webSocket.onEvent(webSocketEvent);

  // handle index
  server.on("/", []() {
      server.send(200, "text/html", pagina);
  });

  server.begin();

  digitalWrite(LED_RED,   1); // 1 = apagado
  digitalWrite(LED_GREEN, 1);
  digitalWrite(LED_BLUE,  1);

  analogWriteRange(255);

}

void loop() {
    webSocket.loop();
    server.handleClient();
}


Librería: https://github.com/Links2004/arduinoWebSockets

15 comentarios:

  1. Felicitaciones Alejandro, bien explicado. Un abrazo.

    ResponderEliminar
  2. Muchas gracias Eduardo. Un Abrazo.

    ResponderEliminar
  3. Estupenda práctica. Habrá que probarla y darla uso para otros proyectos!!!

    ResponderEliminar
  4. Al compilarlo me da error en esta linea "ESP8266WebServer server = ESP8266WebServer(80);"

    alguna sugerencia de lo que esta pasando?

    ResponderEliminar
    Respuestas
    1. Seguramente no tenés instalada la librería WebSocketsServer.h

      Fijate 6:15 del video.

      Saludos.

      Eliminar
    2. Cambiala por "ESP8266WebServer server (80);"

      Eliminar
  5. Hola, aqui les dejo un video de un sketch y un aplicacion que hice para entrar en modo update sin botones ni conexion usb y tambien para introducir ssid y password del wifi, y tb ver el ip para entrar en el esp32 como server en el buscador. Saludos
    https://youtu.be/tmzaNyIRSQc

    ResponderEliminar
  6. Hola, he tenido este problema durante la última semana.
    Build options changed, rebuilding all
    Archiving built core (caching) in: C:\Users\IMG_ES~1\AppData\Local\Temp\arduino_cache_107179\core\core_esp8266_esp8266_nodemcuv2_CpuFrequency_80,VTable_flash,FlashSize_4M1M,LwIPVariant_v2mss536,Debug_Disabled,DebugLevel_None____,FlashErase_none,UploadSpeed_115200_76bf34e4e89342aca1e542b486e62540.a
    Sketch uses 302380 bytes (28%) of program storage space. Maximum is 1044464 bytes.
    Global variables use 32948 bytes (40%) of dynamic memory, leaving 48972 bytes for local variables. Maximum is 81920 bytes.
    warning: espcomm_sync failed
    error: espcomm_open failed
    error: espcomm_upload_mem failed
    error: espcomm_upload_mem failed

    Alguna solución? Porfa, necesito esto. Gracias!

    ResponderEliminar
  7. Probá con otro cable, después con otra placa y si funciona la nueva placa nunca más usés el cable viejo. Me paso de un cable malo que me dañaba las placas y empezaban a tirar ese error. Saludos.

    ResponderEliminar
  8. Hola, saludos desde Brasil, felicitaciones por tu manera sencilla de enseñar y de compartir conocimiento. Un abrazo!

    ResponderEliminar
  9. Hola Alejandro, estoy implementando mediante cloudmqtt el control de LEDs RGB, utilizo la librería RGBMood y empleo el encendido al azar, no puedo implementar la selección de un color desde un "Color picker", llega al nodemcu en formato #xxxxxx (HEX) ó xxx,xxx,xxx (RGB), ¿cómo podría enviar ese dato a las salidas?, quise utilizar if(payload[0] == '#') y el proceso de conversión analogWrite(D6, abs(255 - (rgb >> 16) & 0xFF) ); pero no funciona. Muchas gracias

    ResponderEliminar
  10. Buenas tardes alejandro,muy buen video...
    se puede aplicar websocket en un servidor externo?

    ResponderEliminar
  11. Buenísimo!. Muchas gracias.
    Saludos Cordiales,
    Juan

    ResponderEliminar
  12. se podra en mucho led rgb es para utilizar una base de led de techo que se quemaron los led que tenia y queria utilizar esa base y si se podra

    ResponderEliminar