LoPy© & Pysense© MQTT

LoPy© & Pysense© MQTT

Ejemplo de programación LoPy para el protocolo de red WIFI y el protocolo MQTT, con la publicación de estados de sus sensores y la suscripción a topic de estado led, encendiendo remotamente este, también la suscripción a color led para controlar el color de salida del led, y modo de uso automático o manual para el encendido y apagado del led manualmente o automáticamente al bajar de un umbral de luminosidad.

Estructura del proyecto

El proyecto tiene la siguiente estructura:

README.md(este fichero): describe el proyecto en sí.

pymakr.conf: fichero de configuración para el plug-in Pymakr de Atom o Visual Code.

code/: Contiene los ficheros necesarios para la aplicación a desarrollar para el microcontrolador LoPy©

code/lib/: Directorio con todas librerías y módulos en MicroPython que pueden ser necesarios importar en nuestro programa.

code/boot.py: Programa ejecutado en primer lugar por el micro-controlador LoPy© cuando arranca. Básicamente configura los parámetros de comunicación por el puerto serie y llama a la ejecución del programa main.py

code/main.py: Fichero con todo el código fuente. (a continuación )

Definición de librerías

En el siguiente código se utilizarán las librerías para la lectura de sensores e inicialización de estas:

from pysense import Pysense # playa Pysense de SENSORES
from SI7006A20 import SI7006A20 # SENSOR DE TEMPERATURA y Humedad
from LTR329ALS01 import LTR329ALS01 # SENSOR DE LUMINOSIDAD
py = Pysense()    # OBJETO A PLACA PYSENS
si = SI7006A20(py)  # SENSOR DE TEMPERATURA y Humedad
li = LTR329ALS01(py)  # SENSOR DE LUMINOSIDAD

A continuación la declaración de la Wifi:

_MI_WIFI_SSID_casa="WIFI1"
_MI_WIFI_SSID_casa_PASS= "XXXXX"

def fun_ConfigurarMultiplesWifis():
    global _MQTT_IP  # necesario ya que según la red el servidor cambiara.

    wlan = WLAN(mode=WLAN.STA)
    nets = wlan.scan()
    print('> Buscando Redes ... ')
    for net in nets:
        red_OK=""
        # dependiendo de la red encontrada, configuro parámetros wifi y mqtt
        if net.ssid==_MI_WIFI_SSID_casa:
            print('>> red encontrada: ' + _MI_WIFI_SSID_casa)
            red_OK=_MI_WIFI_SSID_casa  
            passw  = _MI_WIFI_SSID_casa_PASS           
            break # exit for        
            
        #... se puede ampliar con más configuraciones

    if red_OK != "":
        # conectando a red Wifi  
        #           
        print(">>> configurando red ")
        wlan.init(mode=WLAN.STA)
        #  SI FUERA NECESARIO ASIGNAR IP: 
        #       wlan.ifconfig(config=(_MI_IP,_MI_MASCARA_SUBRED,_MI_PUERTA_ENLACE,_MI_DNS)) 
        wlan.connect(red_OK, auth=(WLAN.WPA2, passw), timeout=5000)
        print(">>>> conectando",end='')
        while not wlan.isconnected():
            time1.sleep(1)
            print(".",end='')            
        print("<")
        print(">>>>>> conectado a " + red_OK)

La siguiente función la usaremos para la conexión al servidor MQTT, (MOSQUITO por ejemplo) y la suscripción a los topics:


def fun_ConfigurarMQTT():
    global clientMQTT 
    print ('> conectando a Servidor MQTT ' + _MQTT_IP)
    clientMQTT = MQTTClient(_MQTT_ID, _MQTT_IP, _MQTT_PUERTO)
    # clientMQTT.DEBUG = True
    clientMQTT.set_callback(fun_Callback_Mqtt)
    clientMQTT.settimeout = _MQTT_settimeout
    clientMQTT.connect()
    print(">> MQTT Conectado a " + _MQTT_IP)

    # Realizar suscripciones
    clientMQTT.subscribe(_MQTT_TOPIC_LED) 
    clientMQTT.subscribe(_MQTT_TOPIC_LED_AUTOMATICO) 
    clientMQTT.subscribe(_MQTT_TOPIC_LED_COLOR) 

Declaramos la función CallBack para cuando nos notifique el servidor MQTT una respuesta a la suscripción.

def fun_Callback_Mqtt(topic,msg):
    # llamada siempre que hay un mensaje de suscripción
    global _MQTT_valor_LED
    global _MQTT_valor_LED_AUTOMATICO
    global _MQTT_valor_LED_COLOR

    print('--- callback recibido --- ')
    print(topic)
    print(msg)
    print('---  ---   ---  ---  --- ')

    if topic==b"home/led/onoff":      
        print(' **** en home/led/onoff  ')
        if (msg==b"true"): 
            _MQTT_valor_LED = True
            print(' **** **** led ON  '  ) 
        else:
            _MQTT_valor_LED = False
            print(' **** **** led OFF  '  ) 

    if topic==b"home/led/automatico":  
        print(' **** en home/led/automatico  '  ) 
        if (msg==b"true"):  
            _MQTT_valor_LED_AUTOMATICO = True
            print(' **** **** automatico = True  '  ) 
        else:
            _MQTT_valor_LED_AUTOMATICO = False
            print(' **** **** automatico = False  '  ) 

    if topic==b"home/led/color": 
        print(' **** en home/led/color  '  ) 
        v=msg.decode()        
        hexadecimal_string = int(v,16)
        _MQTT_valor_LED_COLOR = hexadecimal_string  #.decode()# int()
        print(" **** **** cambio color led: " + str(_MQTT_valor_LED_COLOR))

Por último tratamos los led en respuesta a las suscripciones, desde una nueva función


def fun_TratarLed():    
    if _MQTT_valor_LED_AUTOMATICO:
        # MODO AUTOMÁTICO
        # Leo el umbral de luminosidad si es bajo=false (enciendo led) o alto=true (apago led)
        #print("led automatico True")   
        if _MQTT_valor_LED_AUTOMATICO_luminosidad:
            # luminosidad true = alta, apago led
            pycom.heartbeat(False)   
            #print("a led off ")
        else:
            # luminosidad false = Baja, enciendo led                               
            pycom.rgbled(_MQTT_valor_LED_COLOR)  
            #print("a led on")    
            
    else:
        #Si el modo es MANUAL LEO EL ESTADO on/off de _MQTT_valor_LED
        #print("led automatico false")                                            
        if _MQTT_valor_LED:
            pycom.rgbled(_MQTT_valor_LED_COLOR) 
        else:
            pycom.heartbeat(False)   

Y el cuerpo del programa llamando constantemente a la función de publicación y escuchando las respuestas de los topics suscritos:

while True:
    # BUCLE DEL PROGRAMA

    # Publico constantemente la Temp y luminosidad
    publicar = fun_EnviarTemperaturaLuminosidad()
    clientMQTT.publish(topic=_MQTT_TOPIC_TEMPLUMI, msg=publicar)
    print(publicar)

    # ESCUCHO A LAS SUSCRIPCIONES
    clientMQTT.check_msg()  
    
    # Cambio estados del led
    fun_TratarLed()

    time1.sleep(1) 

Código completo main.py

#      =====================================================
#      =========  LoPy4 publicacion MQTT =========
#      =====================================================
import pycom
import machine   # controla es soft reset
import time
import _thread 
import json

from network import WLAN
from mqtt import MQTTClient

from pysense import Pysense # playa Pysense de SENSORES
from SI7006A20 import SI7006A20 # SENSOR DE TEMPERATURA y Humedad
from LTR329ALS01 import LTR329ALS01 # SENSOR DE LUMINOSIDAD

# ----- -----  Variables  ----- ----- 

#  -- ES EL UMBRAL PARA DEFINIR MUCHA O POCA LUZ
#  -- ES DE 200 TAN ALTO YA QUE CUANDO ENCIENDE LOS LED EN AZUL ME SALTABA A 144
#  -- Y EL LED PARPADEABA SI EL UMBRAL ERA INFERIOR
_UMBRAL = 200 
# ----- -----  Variables WIFI  ----- ----- +

_MI_WIFI_SSID_casa="WIFI1"
_MI_WIFI_SSID_casa_PASS= "XXXXX"

_MI_WIFI_SSID_movil= 'WIFI2'
_MI_WIFI_SSID_movil_PASS= 'xxxxx'

_MI_WIFI_SSID_UCLM= 'WIFI3'
_MI_WIFI_SSID_UCLM_PASS= 'XXXXX'


wlan = WLAN()
wlan.antenna(WLAN.EXT_ANT)  # si la antena externa conectada


# ----- -----  Variables MQTT  ----- ----- +

_MQTT_ID = "LoPy21"               #identificador del Dispositivo LOPY
_MQTT_IP_casa = "192.168.1.X"    # IP SERVIDOR MQTT en red Casa y movil
_MQTT_IP_UCLM = "192.168.2.X"     # IP asignada SERVIDOR MQTT en UCLM
_MQTT_IP = ""                     # IP DEFINITIVA DEL SERVIDOR MQTT. Calculada en la conexión WIFI
_MQTT_PUERTO = 1883               # PUERTO servidor MQTT


_MQTT_settimeout = 10                   # timeout al tiempo de intento de conexion server Mqtt
_MQTT_TOPIC_TEMPLUMI = "home/temp_lumi" # publicación topic: publicación de temperatura y luminosidad
_MQTT_TOPIC_LED = "home/led/onoff"      # subscripción topic: led encendido ON OFF  
_MQTT_valor_LED = False                 # Estado inicial del LED (on/off :: true/false)
_MQTT_TOPIC_LED_AUTOMATICO = "home/led/automatico" # subscripción topic: led AUTOMÁTICO/MANUAL
_MQTT_valor_LED_AUTOMATICO = False      # Estado inicial modo  (AUTOMA/MANUAL :: true/false)
_MQTT_TOPIC_LED_COLOR = "home/led/color" # subscripción topic: led COLOR
_MQTT_valor_LED_COLOR = 0x0000ff         # COLOR INICIAL LED azul
_MQTT_valor_LED_AUTOMATICO_luminosidad = False # umbral de luminosidad (Alta/Baja :: True/False)

# ----- -----  INICIALIZAR
time1 = time

py = Pysense()    # OBJETO A PLACA PYSENS
si = SI7006A20(py)  # SENSOR DE TEMPERATURA y Humedad
li = LTR329ALS01(py)  # SENSOR DE LUMINOSIDAD

# ----- -----  ---------  ----- ----- 
# ----- -----  FUNCIONES  ----- ----- 
# ----- -----  ---------  ----- ----- 
# ----- -----  WIFI  ----- ----- 

def fun_ConfigurarMultiplesWifis():
    global _MQTT_IP  # necesario ya que según la red el servidor cambiara.

    wlan = WLAN(mode=WLAN.STA)
    nets = wlan.scan()
    print('> Buscando Redes ... ')
    for net in nets:
        red_OK=""
        # dependiendo de la red encontrada, configuro parámetros wifi y mqtt
        if net.ssid==_MI_WIFI_SSID_casa:
            print('>> red encontrada: ' + _MI_WIFI_SSID_casa)
            red_OK=_MI_WIFI_SSID_casa  
            passw  = _MI_WIFI_SSID_casa_PASS
            _MQTT_IP = _MQTT_IP_casa  # asigno la IP de servidor MQTT de casa
            break # exit for        
            
        if net.ssid==_MI_WIFI_SSID_movil:
            print('>> red encontrada: ' + _MI_WIFI_SSID_movil)
            red_OK=_MI_WIFI_SSID_movil  
            passw  = _MI_WIFI_SSID_movil_PASS
            _MQTT_IP = _MQTT_IP_casa # asigno la IP de servidor MQTT de casa
            break # exit for
        
        if net.ssid==_MI_WIFI_SSID_UCLM:
            print('>> red encontrada: ' + _MI_WIFI_SSID_UCLM)
            red_OK = _MI_WIFI_SSID_UCLM  
            passw  = _MI_WIFI_SSID_UCLM_PASS
            _MQTT_IP = _MQTT_IP_UCLM  # asigno la IP de servidor MQTT UCLM
            break # exit for

    if red_OK != "":
        # conectando a red Wifi  
        #           
        print(">>> configurando red ")
        wlan.init(mode=WLAN.STA)
        #  SI FUERA NECESARIO ASIGNAR IP: 
        #       wlan.ifconfig(config=(_MI_IP,_MI_MASCARA_SUBRED,_MI_PUERTA_ENLACE,_MI_DNS)) 
        wlan.connect(red_OK, auth=(WLAN.WPA2, passw), timeout=5000)
        print(">>>> conectando",end='')
        while not wlan.isconnected():
            time1.sleep(1)
            print(".",end='')            
        print("<")
        print(">>>>>> conectado a " + red_OK)

# ----- -----  ---------  ----- ----- 
# ----- -----  FUNCIONES SENSORES  ----- ----- 
# ----- -----  ---------  ----- ----- 


def fun_EnviarTemperaturaLuminosidad():
    # Leer valores de temperatura y luminosidad
    # Montar json con ello:
    # si luminosidad baja encender led
    global _MQTT_valor_LED_AUTOMATICO_luminosidad
    temperatura= si.temperature()
    luminosidad= li.light()
    if (luminosidad[0] < _UMBRAL) and (luminosidad[1] < _UMBRAL):
            #print(" Luminosidad BAJA")                       
            _MQTT_valor_LED_AUTOMATICO_luminosidad = False
    else:
            #print(" Luminosidad alta")  
            _MQTT_valor_LED_AUTOMATICO_luminosidad = True
    Devolver = json.dumps({'temperatura': temperatura, 'luminosidad0': luminosidad[0], 'luminosidad1': luminosidad[1]})            
    return Devolver
    # SI LED AUTOMÁTICO ACTIVADO Y LUMINOSIDAD BAJA ENCIENDE LED
    

             

# ----- -----  ---------  ----- ----- 
# ----- -----  FUNCIONES MQTT  ----- ----- 
# ----- -----  ---------  ----- ----- 

def fun_ConfigurarMQTT():
    global clientMQTT 
    print ('> conectando a Servidor MQTT ' + _MQTT_IP)
    clientMQTT = MQTTClient(_MQTT_ID, _MQTT_IP, _MQTT_PUERTO)
    # clientMQTT.DEBUG = True
    clientMQTT.set_callback(fun_Callback_Mqtt)
    clientMQTT.settimeout = _MQTT_settimeout
    clientMQTT.connect()
    print(">> MQTT Conectado a " + _MQTT_IP)

    # Realizar suscripciones
    clientMQTT.subscribe(_MQTT_TOPIC_LED) 
    clientMQTT.subscribe(_MQTT_TOPIC_LED_AUTOMATICO) 
    clientMQTT.subscribe(_MQTT_TOPIC_LED_COLOR) 
       
def fun_Callback_Mqtt(topic,msg):
    # llamada siempre que hay un mensaje de suscripción
    global _MQTT_valor_LED
    global _MQTT_valor_LED_AUTOMATICO
    global _MQTT_valor_LED_COLOR

    print('--- callback recibido --- ')
    print(topic)
    print(msg)
    print('---  ---   ---  ---  --- ')

    if topic==b"home/led/onoff":      
        print(' **** en home/led/onoff  ')
        if (msg==b"true"): 
            _MQTT_valor_LED = True
            print(' **** **** led ON  '  ) 
        else:
            _MQTT_valor_LED = False
            print(' **** **** led OFF  '  ) 

    if topic==b"home/led/automatico":  
        print(' **** en home/led/automatico  '  ) 
        if (msg==b"true"):  
            _MQTT_valor_LED_AUTOMATICO = True
            print(' **** **** automatico = True  '  ) 
        else:
            _MQTT_valor_LED_AUTOMATICO = False
            print(' **** **** automatico = False  '  ) 

    if topic==b"home/led/color": 
        print(' **** en home/led/color  '  ) 
        v=msg.decode()        
        hexadecimal_string = int(v,16)
        _MQTT_valor_LED_COLOR = hexadecimal_string  #.decode()# int()
        print(" **** **** cambio color led: " + str(_MQTT_valor_LED_COLOR))

# ----- -----  ---------  ----- ----- 

def fun_TratarLed():    
    if _MQTT_valor_LED_AUTOMATICO:
        # MODO AUTOMÁTICO
        # Leo el umbral de luminosidad si es bajo=false (enciendo led) o alto=true (apago led)
        #print("led automatico True")   
        if _MQTT_valor_LED_AUTOMATICO_luminosidad:
            # luminosidad true = alta, apago led
            pycom.heartbeat(False)   
            #print("a led off ")
        else:
            # luminosidad false = Baja, enciendo led                               
            pycom.rgbled(_MQTT_valor_LED_COLOR)  
            #print("a led on")    
            
    else:
        #Si el modo es MANUAL LEO EL ESTADO on/off de _MQTT_valor_LED
        #print("led automatico false")                                            
        if _MQTT_valor_LED:
            pycom.rgbled(_MQTT_valor_LED_COLOR) 
        else:
            pycom.heartbeat(False)   

# ----- -----  ---------  ----- ----- 
# ----- -----  CUERPO DEL PROGRAMA  ----- ----- 
# ----- -----  ---------  ----- ----- 
# ----- -----  ---------  ----- ----- 

print(" =========================== ") 
print(" =====   LoPy4 v.2  ======== ") 
print(" =========================== ") 

print(" .. Wifi ..")
fun_ConfigurarMultiplesWifis()

print(" .. MQTT .. ")
fun_ConfigurarMQTT()

# Apago el led INICIALMENTE
pycom.heartbeat(False)
print ("-------------------------------------------------------")
print ("------------ COMIENZA LA EJECUCION --------------------")
print ("------- led  OFF MODO AUTOMATICO OFF color AZUL     ---")
print ("-------------------------------------------------------")
while True:
    # BUCLE DEL PROGRAMA

    # Publico constantemente la Temp y luminosidad
    publicar = fun_EnviarTemperaturaLuminosidad()
    clientMQTT.publish(topic=_MQTT_TOPIC_TEMPLUMI, msg=publicar)
    print(publicar)

    # ESCUCHO A LAS SUSCRIPCIONES
    clientMQTT.check_msg()  
    
    # Cambio estados del led
    fun_TratarLed()

    time1.sleep(1) 

Puesta en marcha

Se utilizará el editor Visual Code o Atom, en ambos es compatible la librería Pymakr.

En el caso de Visual Code la podemos instalar directamente desde su instalador de plugins buscándola como Pymakr.

Una vez instalado Pymakr y desde el raiz del proyecto, conectamos Lopy4 por usb y nos lo reconocerá inmediátemente.

NOTA: en el archivo pymakr.conf la primera linea: “address”: “COM4” sustituir COM4 por el puerto en el que detecte la librería pymakr al controlador LOPY4.

En visual Code aparecerá una barra de estado Pymakr en el pie del editor, con las comandos de Pymakr para ejecutar y cargar el código en Lopy4.

Mediante el comando RUN podemos lanzar el código a Lopy4. Mediante el comando Upload lanzamos el código a la memoria flash de Lopy4.

Para parar un proyecto en marcha:

CTRL-C: Stop any running code

CTRL-D: soft reset

Tambien tenemos los códigos, desde la linea de comandos (Atom o Visual Code) para flasear la memoria:

import os
os.fsformat('/flash')

Lanzar un reset

import machine
machine.reset()

o preguntar por la IP asignada por el controlador LoPy4

wlan.ifconfig()

PROYECTO COMPLETO

https://gitlab.com/alqaid/microcontrolador-lopy4

REFERENCIAS

Fabricante Pycom, microcontrolador LoPy4 y placa sensores Pysense: https://pycom.io/

Cómo programar en Python y posibilidad de practicar online: https://www.w3schools.com/python/

Referencia de MicroPython, (aunque la gran mayoría de funciones usadas para programar con microcontroladores, son soportadas por MicroPyton: https://docs.micropython.org/en/latest/

También podemos ver las funcionalidades distintas entre Micropython y Python: https://docs.micropython.org/en/latest/genrst/index.html

Web online entrenador Micropython: https://micropython.org/unicorn/

Otras Publicaciones LoPy de esta web.

https://www.alcaide.info/category/microcontroladores