Motika By CVR | LUA (NodeMcu)

Iniciar con Lua


Node Mcu es un firmware opensource basado en lua para el ESP8266 y ESP32. utiliza un sistema de archivos SPIFFS basado en flash en el módulo. NodeMCU se implementa en C y se superpone en el SDK NON-OS de Espressif.

El modelo de programación de NodeMCU es similar al de Node.js, solo que en Lua. Es asíncrono y está orientado a eventos. Las funciones, por lo tanto, tienen parámetros para funciones de devolución de llamada.

Mas informacion sobre NodeMcu aquí

Construyendo el Firmware
Existen 3 caminos para construir el firmware:

  1. Servicio de construcción en la nube (cloud build service). https://nodemcu-build.com/
  2. Imagende Docker
  3. Entorno Linux (puede usar una máquina virtual)

Si quieres iniciar un poco más rápido, hemos preparado una imagen lista para instalar la cual puedes descargar aquí.

Instalar el Firmware (Flashear)
Instalar imagen en la placa es bastante sencillo. Para esto usaremos una herramienta llamada esptool. Esta herramienta está escrita en python por lo que debemos instalar python en nuestro equipo (descarga python3 aquí).

La herramienta esptool puedes descargarla en el siguiente enlace: https://github.com/espressif/esptool y está soportada por windows, linux, OS X y cualquier sistema operativo que pueda correr python.

Para instalar el firmware es muy importante poner la placa en modo flash, para esto usaremos los pines [flash] en la placa designados para dicho proposito. Usaremos el jumper para poner la placa en modo flash.

img motika jumper position PASO 1:
Ejecutaremos el siguiente comando para borrar la memoria del microcontrolador:

esptool.py --port <serial-port-of-ESP8266> erase_flash
Descripción de los parámetros: <serial-port-of-ESP8266> El puerto serial (COMx Windows, ttyxxx Linux).

PASO 2:
Instalaremos la imagen con un simple comando en nuestra placa. Para lo que conectaremos nuestra placa a nuestro PC y abrimos una consola de de comandos (terminal) y digitamos el siguiente comando:
esptool.py --port <serial-port-of-ESP8266> write_flash -fm <flash-mode> -fs 4MB 0x00000 <nodemcu-firmware.bin>
Descripción de los parámetros:
<serial-port-of-ESP8266> : El puerto serial (COMx Windows, ttyxxx Linux)
<flash-mode> qio (ESP-01/07 modulos de 512kByte) | dio (ESP-12 módulos de 4 MByte o más) | dio (ESP8285)
<nodemcu-firmware>.bin (Ruta y nombre del archivo que contiene la imagen).

Ejemplo:
esptool.py --port COM3 write_flash -fm dio 0x00000 -fs 4MB C:\lua.bin
Una vez terminado el proceso podemos verificar que el firmware ha sido instalado correctamente abriendo un terminal serial ( configurar baudios en 115200) y presionando el botón reset de la placa. En el terminal veremos lo siguiente:

imagen de lo que se va a mostrar en la terminal

Ahora estámos listos para iniciar a programar nuestra placa Motika usando NodeMcu, iniciemos con los siguientes tutoriales:

  1. Escribiendo código.
  2. Cargar código a la placa.
  3. Conectar a red wifi.
  4. Crear red wifi.
  5. Controlando cargas.
  6. Crear servidor HTTP para controlar cargas.
  7. Crear socket TCP-IP para controlar cargas
  8. Pines I/O de propósito general.

Escribiendo código
Podemos escribir nuestro código en cualquier editor, lo importante es tener en cuenta que el archivo donde escribimos nuestro código sea de extensión .lua Es importante resaltar que nuestro archivo contenedor del script puede tener cualquier nombre, pero si queremos que nuestro script se ejecute en el inicio una vez la placa sea conectada nuestro archivo debe tener el nombre init.lua Cargando código a la placa.

Existen diferentes alternativas para cargar el código a la placa como nodemacu-uploader.py(escrita en python) y NodeMCU-Tool pero la más usada por su facilidad y flexibilidad es ESPlorer (Java) este es un pequeño IDE que nos permite escribir código y subirlo directamente a la placa sin necesidad de aplicaciones externas. Descargar ESPlorer: https://github.com/4refr0nt/ESPlorer.

Más documentación sobre como subir código a la placa: https://nodemcu.readthedocs.io/en/release/upload/

Escribiendo código
Motika está basada en el ESP8266, este microcontrolador cuenta con un chip wifi configurable el cual permite conectarse a una red wifi existente (MODO AP) o crear una red wifi desde el propio módulo (MODO STATION) permitiendo así comunicarnos con dispositivos externos mediante protocolos de comunicaciones IP . Toda la informacion sobre wifi en: https://nodemcu.readthedocs.io/en/release/modules/wifi/

Conceptos generales de wifi (esto puede ser un modal)



Conectar a red wifi.
(ver antes conceptos generales de wifi)

Conectar con una red wifi es muy fácil, para esto usaremos el siguiente código:

wifi.setmode(wifi.STATION)

SSID = "ceenford-latinoamerica"
PASS = "44442832"

station_cfg={}
station_cfg.ssid = SSID
station_cfg.pwd = PASS
station_cfg.save = true

wifi.sta.config(station_cfg)
wifi.sta.connect()


Primero creamos una variable de tipo objeto que almacena los parámetros de configuración.

ssid = Nombre de la red wifi a la que se conectará
pwd = Clave de la red
save = ¿se almacenará la configuración en la flash?

Se configura el módulo como STATION para conectar a una red wifi existente y luego se pasa la variable que contiene la configuración a la función wifi.sta.config(station_cfg) encargada de establecer la configuración en el módulo. Una vez establecida la configuración procedemos a llamar la función wifi.sta.connect() la cual inicia la conexión. Esta función puede recibir como parámetro un callback [connected_cb] el cual se ejecutará cuando la conexión sea establecida. Ejemplo: wifi.sta.connect([connected_cb]).

A continuacion se muestra el codigo completo para conectar a una red wifi y verificar el estado de la conexión.

                

wifi.setmode(wifi.STATION) SSID = "nombre de la red" PASS = "clave de la red" station_cfg = {} station_cfg.ssid = SSID station_cfg.pwd = PASS station_cfg.save = true wifi.sta.config(station_cfg) wifi.sta.connect() awaitTime = 0 print("Conectando a la red wifi, espere...") tmr.alarm(1, 1000, 1, function() if wifi.sta.getip() == nil then awaitTime = awaitTime + 1 if awaitTime > 20 then print("falló la conexion a la red wifi") tmr.stop(1) end else print("IP del modulo Motika "..wifi.sta.getip()) print("conectado a la red "..SSID) tmr.stop(1) end end )

Crear red wifi.
(ver antes conceptos generales de wifi)

wifi.setmode(wifi.SOFTAP)

cfg={}
cfg.ssid="myssid"
cfg.pwd="mypassword"

wifi.ap.config(cfg)

Primero creamos una variable de tipo objeto que almacena los parámetros de configuración.

ssid = Nombre de la red wifi a la que se conectará
pwd = Clave de la red

Se configura el módulo como AP para crear redes wifi y luego se pasa la variable que contiene la configuración a la función wifi.ap.config(cfg) encargada de establecer la configuración en el módulo. Con esto ya podríamos verificar la existencia de una nueva red wifi con nombre y clave establecidos en cualquier dispositivo con conexión wifi.

Creando Socket TCP/IP

Un socket TCP-IP permite la comunicación de nuestra placa con cualquier software o aplicación. Crear uno es bastante facil.

                    

ss = net.createServer(net.TCP,1000) ss:listen(8080, function(conn) conn:on("receive", receiver) end )

net.createServer Recibe como parámetros el tipo de servidor (TCP/UDP) y el tiempo de espera para estabilizar la conexión. Eta función devuelve un socket el cual es almacenado en la variable ss.

ss:listen Recibe como parámetros el puerto donde se escuchará la conexión y una funcion donde luego procesaremos los datos recibidos desde el cliente.
A continuación se muestra el códico completo para crear un socket TCP/IP en la red wifi. La conexión se escuchará en el puerto 8080 pero puedes modificar el valor del puerto por el que gustes.

                

wifi.setmode(wifi.STATION) SSID = "nombre de la red" PASS = "clave de la red" station_cfg = {} station_cfg.ssid = SSID station_cfg.pwd = PASS station_cfg.save = true wifi.sta.config(station_cfg) wifi.sta.connect() awaitTime = 0 print("Conectando a la red wifi, espere...") tmr.alarm(1, 1000, 1, function() if wifi.sta.getip() == nil then awaitTime = awaitTime+1 if awaitTime > 20 then print("falló la conexion a la red wifi") tmr.stop(1) end else print("IP del modulo Motika "..wifi.sta.getip()) print("conectado a la red "..SSID) ss=net.createServer(net.TCP,1000) ss:listen(8080, function(conn) conn:on("receive", receiver) end ) tmr.stop(1) end end ) function receiver(sck, data) print(data) response = "Hola soy tu placa Motika By CVR" sck:send(response) end

Controlando Cargas:
Motika, cuenta con 4 relés mecánicos en placa con posibilidad de control de 8 canales de relé (P4-P7) y hasta 16 canales (agregando módulo de expansión de 8 canales extra) completamente aislados del microcontrolador y controlados por el módulo de expansión PCF8574. permitiendo el control de las cargas haciendo uso de solo 2 pines del microcontrolador (I2C). A continuación el código de muestra para el control de cargas mediante el uso de relés.

Para facilitar el uso de los relés en placa hemos desarrollado un script que se encarga del control de los mismos. Este script debe ser cargado a la placa y ejecutado en la primera linea para cargar sus funciones.
A continuación el escript pcf8574_control.lua

                

PCF8574_address = 0x20 last_byte = 0 function pcf8574_init(init,SDA,SCL) --inicializa el bus i2c id = 0 pinSDA = SDA --4 pinSCL = SCL --3 speed = i2c.SLOW if init then i2c.setup(id, pinSDA, pinSCL, speed) end PCF8574_clear() end function PCF8574_clear() writeToPCF(0) last_byte = 0 end function writeToPCF(byte) --escribe los datos al pcf8574 modulo vía i2c i2c.start(id) i2c.address(id, PCF8574_address,i2c.TRANSMITTER) i2c.write(id,byte) i2c.stop(id) end function on_io(pin) last = string.byte(get_io()) bases = {0x1,0x2,0x4,0x8,0x10,0x20,0x40,0x80} if pin == "all" then nb = bit.band(0xFF,255) writeToPCF(nb) last_byte = 255 elseif pin > 0 and pin < 9 then nuevo = bit.bor(bases[pin],last) writeToPCF(nuevo) last_byte = nuevo end end function off_io(pin) last_off = last_byte bases_off = {0xFE,0xFD,0xFB, 0xF7,0xEF,0xDF,0xBF,0x7F} if pin =="all" then writeToPCF(0) last_byte = 0 elseif pin > 0 and pin < 9 then nuevo_off = bit.band(bases_off[pin],last_off) writeToPCF(nuevo_off) last_byte = nuevo_off end end function get_io() i2c.start(id) i2c.address(id, PCF8574_address, i2c.RECEIVER) c = i2c.read(id, 1) i2c.stop(id) return c end

Una vez cargado el script podemos controlar cargas haciendo uso de los relés integrados en la placa.

El siguiente codigo activa y desactiva cada uno de los relé de forma secuencial.

                

pcf8574_init(true,4,3) PCF8574_clear() on_io(1) tmr.delay(1000) on_io(2) tmr.delay(1000) on_io(3) tmr.delay(1000) on_io(4) tmr.delay(4000) off_io(1) tmr.delay(1000) off_io(2) tmr.delay(1000) off_io(3) tmr.delay(1000) off_io(4) tmr.delay(1000)

Controlando cargas vía TCP-IP

Por ultimo, dejaremos un ejemplo completo en el que se mostrará como controlar cargas desde el modulo Motika desde cualquier cliente TCP/IP por medio de la red wifi.

Recuerda que esta es solo una pequeña aplicación para instruirte sobre como funciona la placa, pero con tu imaginación podrás hacer cualquier cosa.

                

dofile("pcf8574_control.lua") pcf8574_init(true,4,3) PCF8574_clear() wifi.setmode(wifi.STATION) SSID = "Nombre de la red" PASS = "Clave de la red" station_cfg = {} station_cfg.ssid = SSID station_cfg.pwd = PASS station_cfg.save = true wifi.sta.config(station_cfg) wifi.sta.connect() awaitTime = 0 print("Conectando a la red wifi, espere...") tmr.alarm(1, 1000, 1, function() if wifi.sta.getip() == nil then awaitTime = awaitTime+1 if awaitTime > 20 then print("falló la conexion a la red wifi") tmr.stop(1) end else print("IP del modulo Motika "..wifi.sta.getip()) print("conectado a la red "..SSID) ss=net.createServer(net.TCP,1000) ss:listen(8080, function(conn) conn:on("receive", receiver) end ) tmr.stop(1) end end ) function receiver(sck, data) print("Datos recibidos: "..data) response = " " if data == "OnCharge1" then on_io(1) response = "Carga #1 encendida" elseif data == "OnCharge2" then on_io(2) response = "Carga #2 encendida" elseif data == "OnCharge3" then on_io(3) response = "Carga #3 encendida" elseif data == "OnCharge4" then on_io(4) response = "Carga #4 encendida" elseif data == "OffCharge1" then off_io(1) response = "Carga #1 encendida" elseif data == "OffCharge2" then off_io(2) response = "Carga #2 encendida" elseif data == "OffCharge3" then off_io(3) response = "Carga #3 encendida" elseif data == "OffCharge4" then off_io(4) response = "Carga #4 encendida" end sck:send(response) end