Servidor Esp8266 con dos leds Version I




Presentación


Este es el primer proyecto donde quiero mostrar como la libreria "uasyncio" nos permite hacer tareas de modo casi silmutáneo.

Debo aclarar que dije casi simultáneo porque en realidad lo que se logra usando esta libreria es que las tareas se vayan intercalando de tal modo que parecen suceder simultaneamente aunque en realidad el proceso se realiza de modo secuencial.

Para desarrollar proyectos con esta libreria basicamente se deben declarar las funciones como asincronicas (async def) e incluir en las mismas el llamado "await".

En el armado de estas funciones debe considerarse que las mismas han de repetirse su ejecucion a lo largo de la ejecución del programa, ya que de terminar la misma dejaran de ser llamadas.

Luego se crea la funcion que administrar todas las rutinas, se le agrega cada rutina y finalmente se ejecuta esta funcion.

En este primer proyecto he considerado las siguientes tareas:

1.- Un servidor web con una pagina que informa el estado de dos led y permite activar o desactivar su encendido y apagado.

2.- Dos rutinas que cada una maneja el encendido y apagado de uno de los led

3.- Una rutina que solo va acumulando un contador para saber cuantos ciclos se han cumplido y si el programa sigue corriendo


Materiales


Placa Wemos D1 R1

Dos Leds


Montaje del proyecto en la placa Wemos D1 R1


Para utilizar la placa Wemos D1 R1 con MicroPython es necesario flashear primero la misma con el firmware correspondiente. En el caso de la utilizada en este modelo se utilizo el "esp8266-20220618-v1.19.1.bin" provisto por la pagina de Firmware ESP8266

Pueden usar esa version o alguna otra de la pagina, no todas las versiones son compatibles con todas las placas segun mi experiencia.

Para flashear la placa lo hago directamente desde un a terminal de linux abierta en la carperta donde trngo el firmware y utilizo la linea de comando: esptool.py --port /dev/ttyUSB0 --baud 460800 write_flash --flash_size=detect -fm dout 0 esp8266-20220618-v1.19.1.bin.

Aqui cabe la misma aclaracion realizada con respecto al firmware, no todas las placas admiten la misma linea de comandos para grabar eñ firmware e incluso algunas lo hacen mejor con aplicaciones como Thonny. Hay que animarse y probar cambios cuando no funciona.

Una vez instalado el firmware en la placa utilizando la utilidad que viene provista por el IDE Thonny, o por aquella que ustedes utilicen elimino el archivo boot.py y copio el codigo que se detalla mas adelante

Ademas deben conectarse a la placa los dos leds conforme el diagrama puesto a continuacion:



Actualizacion al 11/10/23


Habiendome hecho notar a traves del canal de telegram Canal Micropython el usuario Maxi la observacion que al dar varios clic seguidos sobre los botones de activar y des activar se producia el siguiente error "OSError: [Errno 104] ECONNRESET" en principio y para evitar que se produzca el error bloquee la posibilidad de clics sucesivos inmediantos agregando una alert() en el clic del boton. El codigo colocado mas abajo ya esta actualizado.


Código


El código se ha escrito en un unico archivo main.py.




from machine import Pin
import uasyncio
import network
import socket
import time
        
        
red = 'xxxxxxxxxx'
clave = 'xxxxxxxxxxx'
        
pin_04 = Pin(4, Pin.OUT, value=0)
pin_05 = Pin(5, Pin.OUT, value=0)
control1 = False
control2 = False
estado1 = "Inactivo"
estado2 = "Inactivo" 
        
        
def conecta_wifi():
            wifi = network.WLAN(network.STA_IF)
            wifi.active(True)
            wifi.connect(red, clave)
        
            while wifi.isconnected() == False:
                pass
        
            print('Conectada a Wifi')
            print('************************')
            print('RED:     %s' % red)
            print('IP:      %s\nSUBNET:  %s\nGATEWAY: %s\nDNS:     %s' % wifi.ifconfig()[0:4])
            a = wifi.config('mac')
            print('MAC:     {:02x}:{:02x}:{:02x}:{:02x}:{:02x}'.format(a[0],a[1],a[2],a[3],a[4]))
            print('************************')
            
        
        
            
def pagina_web():
             
            html = """
        <!DOCTYPE html>
        <html>
            <head>
                <title>Esp32</title>
                <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
                <meta name="viewport" content="width=device-width, initial-scale=1">
            </head>
            <body align='center'>
                <h1>Servidor Esp8266</h1>
                <br>
                <h3>Estado del Led Verde:</h3>
                <h4 style='color: #27AE60;'>""" + estado1 + """</h4>
                <button id='on' type="button" onclick="window.location.href='/?control1=act'; alert('Ud. activo flash led verde');">ACTIVAR</button>  
                <button id='off' type="button" onclick="window.location.href='/?control1=des'; alert('Ud. desactivo flash led verde');">DESACTIVAR</button>  
                <h3>Estado del Led Rojo:</h3>
                <button id='on' type="button" onclick="window.location.href='/?control2=act'; alert('Ud. activo flash led rojo');">ACTIVAR</button>  
                <button id='off' type="button" onclick="window.location.href='/?control2=des'; alert('Ud. desactivo flash led rojo');">DESACTIVAR</button>  
                <h4 style='color: #E74C3C;'>""" + estado2 + """</h4>
                <script>
                    
                    let segundos_recarga = 2;
                    setTimeout(function() {
                      window.location = "/";
                    }, segundos_recarga * 1000);
                </script>
                
            </body>
        </html>
        """
            return html
        
def servidor():
            global s
            global activar1
            global control1
            global estado1
            global activar2
            global control2
            global estado2
            
            while True:
            
                conexion, ip = s.accept()
                print('Conexion a %s' % str(ip))
                respuesta = conexion.recv(1024)
                conexion.settimeout(None)
                respuesta = str(respuesta)
                #print(respuesta)
            
                
                
                if respuesta.find('/?control1=act') == 6:
                    print('ACTIVA 1')
                    control1 = True
                if respuesta.find('/?control1=des') == 6:
                    print('DESACTIVA 1')
                    control1 = False
                    estado1 = "Inactivo"
                if respuesta.find('/?control2=act') == 6:
                    print('ACTIVA 2')
                    control2 = True
                if respuesta.find('/?control2=des') == 6:
                    print('DESACTIVA 2')
                    control2 = False
                    estado2 = "Inactivo"
                conexion.send('HTTP/1.1 200 OK\n')
                conexion.send('Content-Type: text/html\n')
                conexion.send('Connection: close\n\n')
                conexion.sendall(pagina_web())
                await uasyncio.sleep(1)
            
        
        
        
        
def iniciar_servidor():
            global s
            s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            s.bind(('', 80))
            s.listen(5)
            print('Servidor funcionando...!\n***************************\n')
        
async def rutina2():
            
            contador = 0                      
            while True:               
                print("contador")
                print(contador)
                await uasyncio.sleep(1)
                contador +=1         
                
        
        
        
async def rutina3():
            global control1
            global estado1             
            while True:
                if (control1 == True):
                    pin_04.on()
                    print("pin4 on")
                    estado1 = "Encendido"
                    await uasyncio.sleep(3)
                    pin_04.off()
                    print("pin4 off")
                    estado1 = "Apagado"
                else:
                    estado1 = "Inactivo"
                await uasyncio.sleep(3)
         
                
async def rutina4():
            global control2
            global estado2
            while True:
                if (control2 == True):
                    pin_05.on()
                    print("pin5 on")
                    estado2 = "Encendido"
                    await uasyncio.sleep(5)
                    pin_05.off()
                    print("pin5 off")
                    estado2 = "Apagado"
                else:
                    estado2 = "Inactivo"
                await uasyncio.sleep(5)
            
        
conecta_wifi()
        
iniciar_servidor()
        
        
programa = uasyncio.get_event_loop()
programa.create_task(servidor())
programa.create_task(rutina2())
programa.create_task(rutina3())
programa.create_task(rutina4())
programa.run_forever()
              

    


Funcionamiento


Una vez iniciado el programa debemos acceder con un navegador a la IP que nuestra red le haya asignado a la placa y se abrira la siguiente pagina:

En la misma podremos activar alternativamente o en forma simultanea los leds para que empiecen a parpadear cada uno a su propio ritmo y detenerlos cuando deseemos, pudiendo observar asi como la placa realiza tres tareas independientes, el parpadeo de cada led y el funcionamineto del servidor. Asu vez en el monitor serial podremos observar una cuarta tarea que funciona ininterrumpidamente mostrandonos un contador.

La idea de este proyecto mes ejemplificar un modo sencillo de simular tareas simultaneas utilizando la placa Esp8266 y la libreria uasyncio.


Quedo disposición de quien quiera hacerme consultas o sugerencias mi correo electronico es carlosvaccaro1960@gmail.com