En esta práctica se desarrolla un ejemplo de uso del módulo WebSockets de la librería microWebSrv2, para regular la intensidad de un LED con una barra de desplazamiento desde una página Web.
Para llevarla a cabo será necesario:
-
- Haber instalado librería microWebSrv2 en el directorio /lib (u otro directorio en el que el intérprete busque los módulos y librerías complementarios) como se explica en la práctica: MICROPYTHON ESP32 – LIBRERÍAS NO ESTÁNDARES: Servidor WEB con microWebSrv2.
- Utilizar utilizar una placa con un microcontrolador ESP32 que disponga de 8 Mb de memoria psRAM. Con placas como la TTGO – T8 V-1.7 o la TTGO – T8 V-1.8, funcionará perfectamente.
FICHEROS A UTILIZAR
La carpeta comprimida wwwWSLedControl, con los ficheros a utilizar, se puede descargar aquí. Contiene tres ficheros:
- webSocketsLedControl.py sirve para gestionar el servidor y el LED desde el microcontrolador,
- index.html es la página Web que mostrará el navegador y
- favicon.ico es el icono que se verá en la pestaña del navegador.
Una vez descomprimida se debe copiar en el directorio raíz del microcontrolador.
webSocketsLedControl.py
El script es sencillo de entender:
- De la línea 3 a la 16 gestiona la conexión WiFi.
- En las líneas 28 y 29 inicializa el LED situado en la placa built-in PIN21 o un LED conectado en el PIN21.
- De la línea 21 a la 23 importa los módulos y clases del servidor, inicializándolo con una gestión optimizada entre las líneas 86 y 105.
- En las líneas 86 y 87 carga el módulo WebSockets y de la línea 35 a la 40 define la función para aceptar el webSocket.
- De la línea 46 a 78 define las variables y funciones para gestionar la comunicación entre servidor y cliente.
# FUNCIÓN PARA ESTABLECER LA CONEXIÓN WIFI (STATION) def do_connect(SSID, PASSWORD): import network # importa el módulo network global sta_if sta_if = network.WLAN(network.STA_IF) # instancia el objeto -sta_if- para realizar la conexión en modo STA if not sta_if.isconnected(): # si no existe conexión... sta_if.active(True) # activa el interfaz STA del ESP32 sta_if.connect(SSID, PASSWORD) # inicia la conexión con el AP print('Conectando a la red', SSID +"...") while not sta_if.isconnected(): # ...si no se ha establecido la conexión... pass # ...repite el bucle... print('Configuración de red (IP/netmask/gw/DNS):', sta_if.ifconfig()) # ¡¡¡IMPORTANTE!!! do_connect("<nombre_de_red>","<clave_de_red>") # RELLENAR CON EL nombre/clave_de_red # IMPORTA LOS MÓDULOS/CLASES PARA CONTROLAR EL SERVIDOR from MicroWebSrv2 import * # importa el módulo MicroWebSrv2 from time import sleep from _thread import allocate_lock # INICIALIZA EL LED BUILT-IN (PIN 21 - PLACA TTGO-T8 v1.7) from machine import Pin,PWM pwmLED = PWM(Pin(21), freq=78100, duty=512) # ============================================================================ # ============================================================================ # ============================================================================ def OnWebSocketAccepted(microWebSrv2, webSocket) : print('Example WebSocket accepted:') print(' - User : %s:%s' % webSocket.Request.UserAddress) print(' - Path : %s' % webSocket.Request.Path) print(' - Origin : %s' % webSocket.Request.Origin) WSJoinChat(webSocket) # ============================================================================ # ============================================================================ # ============================================================================ global _chatWebSockets _chatWebSockets = [ ] global _chatLock _chatLock = allocate_lock() # ------------------------------------------------------------------------ def WSJoinChat(webSocket) : webSocket.OnTextMessage = OnWSChatTextMsg webSocket.OnClosed = OnWSChatClosed addr = webSocket.Request.UserAddress with _chatLock : _chatWebSockets.append(webSocket) webSocket.SendTextMessage(str(pwmLED.duty())) #Cuanto se inica una conexión envia al cliente la intensidad del LED (0-1023) # ------------------------------------------------------------------------ def OnWSChatTextMsg(webSocket, msg) : addr = webSocket.Request.UserAddress with _chatLock : for ws in _chatWebSockets : #Cuanto un cliente envía un mensaje, el servidor lo reenvía al resto de los clientes... if ws != webSocket : ws.SendTextMessage(msg) pwmLED.duty(int(msg)) #... y se regula la intensidad del LED (0-1023) de acuerdo al mensaje recibido. # ------------------------------------------------------------------------ def OnWSChatClosed(webSocket) : addr = webSocket.Request.UserAddress with _chatLock : if webSocket in _chatWebSockets : _chatWebSockets.remove(webSocket) # ============================================================================ # ============================================================================ # ============================================================================ print() wsMod = MicroWebSrv2.LoadModule('WebSockets') # Carga el módulo WebSockets y lo configura wsMod.OnWebSocketAccepted = OnWebSocketAccepted mws2 = MicroWebSrv2() # Instanciala clase MicroWebSrv2 mws2.RootPath = "/wwwWSLedControl" mws2.SetEmbeddedConfig() # Utiliza una configuración ligera para MicroPython mws2.StartManaged() # Inicia el servidor de una forma sencilla en modo "managed" try : # Ejecuta el programa hasta que el teclado lo interrumpe while mws2.IsRunning : sleep(1) except KeyboardInterrupt : pass # End, print() mws2.Stop() print('Bye') print() # ============================================================================ # ============================================================================ # ============================================================================
Cuando un cliente que esté conectado con el servidor mueva la barra de desplazamiento ocurrirán dos cosas:
- Se actualizará la intensidad del LED.
- Se actualizarán las barras de desplazamiento del resto de los clientes conectados con el servidor.
index.html
El fichero está comentado para poder entender cómo funciona:
<!DOCTYPE html> <html> <head> <title>REGULACIÓN DE LED</title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css"> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.16.0/umd/popper.min.js"></script> <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js"></script> </head> <body> <div class="jumbotron text-center"> <h1>MicroWebSrv2 - Módulo de WebSockets</h1> </div> <div class="container"> <div class="row"> <div class="col-sm-6"> <h4 id="estado">ESTADO: desconectado</h4> <button id="conectando" type="button" class="btn btn-primary btn-block d-none"> <span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span> CONECTANDO </button> <button id="desconectar" type="button" class="btn btn-danger btn-block d-none" onclick="websocket.close()"> DESCONECTAR </button> <button id="conectar" type="button" class="btn btn-primary btn-block d-none" onclick="initWebSocket()"> CONECTAR </button> </div> <div class="col-sm-6"> <form> <h4 id="intensidad">INTENSIDAD (%)</h4> <input id="myRange" type="range" class="custom-range" min="0" max="100" step="1"> </form> </div> </div> </div> <script> // FUNCIONES PARA CONEXIÓN DEL WEBSOCKET Y EVENTOS function initWebSocket() { var wsUri = 'ws://' + window.location.hostname; websocket = new WebSocket(wsUri); websocket.onopen = function(evt) { onOpen (evt) }; websocket.onclose = function(evt) { onClose (evt) }; websocket.onerror = function(evt) { onError (evt) }; websocket.onmessage = function(evt) { onMessage (evt) }; document.getElementById("estado").textContent="ESTADO: conectando a " + wsUri; buttonToShow("conectando") } function onOpen(evt) { document.getElementById("estado").textContent="ESTADO: conectado"; buttonToShow("desconectar") } function onClose(evt) { document.getElementById("estado").textContent="ESTADO: desconectado"; buttonToShow() } function onError(evt) { document.getElementById("estado").textContent="ESTADO: ERROR <span style='color: red;'>" + evt.data + "</span>" buttonToShow() } function onMessage(evt) { var m = scaleValue(evt.data, [0,1023], [0,100]); if (m != 0 && m != 100){++m} //corrección (dato recibido por el cliente = dato enviado por otro cliente) //por redondeos en las comunicaciones se pierde una ud. excepto en el 0 y 100 slider.value = m; textSlider.innerHTML = "INTENSIDAD: " + m + "%"; } function SendMsg(msg) { var n = scaleValue(msg, [0,100], [0,1023]); websocket.send(n); } // ESCALADO DE VALORES [0,100] <--> [0,1023] function scaleValue(value, from, to) { var scale = (to[1] - to[0]) / (from[1] - from[0]); var capped = Math.min(from[1], Math.max(from[0], value)) - from[0]; return ~~(capped * scale + to[0]); // The ~~ trick on return value does the equivalent of Math.floor, just faster. } // GESTIÓN DE LA BARRA DESLIZANTE var slider = document.getElementById("myRange"); var textSlider = document.getElementById("intensidad"); textSlider.innerHTML = "INTENSIDAD: " + slider.value + "%"; slider.oninput = function() { textSlider.innerHTML = "INTENSIDAD: " + this.value + "%"; SendMsg(this.value) } // BOTÓN A VISUALIZAR var a = document.getElementById("conectando"); var b = document.getElementById("desconectar"); var c = document.getElementById("conectar"); function buttonToShow(button){ if (button == "conectando"){ a.classList.remove("d-none"); // Muestra el botón b.classList.add("d-none"); // Oculta el botón c.classList.add("d-none"); // Oculta el botón } else if (button == "desconectar"){ a.classList.add("d-none"); // Oculta el botón b.classList.remove("d-none"); // Muestra el botón c.classList.add("d-none"); // Oculta el botón } else { a.classList.add("d-none"); // Oculta el botón b.classList.add("d-none"); // Oculta el botón c.classList.remove("d-none"); // Muestra el botón } } window.addEventListener("load", initWebSocket, false); </script> </body> </html>
PUESTA EN FUNCIONAMIENTO
Para ejecutar se debe escribir la dirección IP que le asigna el router al microcontrolador en un navegador (Google Chrome, Mozzilla, Microsoft Edge, etc.).
La dirección se puede localizar en la ventana del intérprete (Shell).
Así será como se vean 3 conexiones establecidas de forma simultánea con el servidor:
Leave a Reply
Tu correo electrónico está seguro.
You must be logged in to post a comment.