Instalar un intérprete de Lua en el ESP8266

En ESP8266 y el "internet de las cosas" y Ejemplos de uso de los comandos AT del ESP8266 presento el interesante chip ESP8266, un pequeño pero capaz microprocesador que cuesta menos de 2€ y que incluye capacidad WIFI. El fabricante ha ido soltando información con cuentagotas, en chino (literalmente) y orientada hacia la programación en C, pero algunos valientes han implementado cosas como Forth (1 y 2).

Forth es un lenguaje muy interesante del que guardo buenos recuerdos, pero en este artículo veremos cómo instalar Lua en un ESP8266. En concreto la implementación de Lua de NodeMCU.

esp8266.jpg

En condiciones normales habría que instalar el SDK del ESP8266, descargar el código de Lua de NodeMCU y compilarlo. Afortunadamente existe un proyecto para hacer eso online: NodeMCU custom builds.

Este proyecto nos permite elegir entre la versión estable o la versión en desarrollo de Lua de NodeMCU, si queremos una versión que soporte coma flotante o no, así como seleccionar los módulos a incluir. Los módulos son importantes por varios motivos:

  • Los módulos son las extensiones de Lua que nos permiten acceder al Hardware y a las capacidades del Firmware del ESP8266. Por ejemplo, para conectarnos por WIFI o acceder al bus I2C.

  • Aunque mi versión del ESP8266 incluye 4MB de memoria Flash, parece que la versión de Lua compilada con NodeMCU custom builds genera binarios incorrectos que no funcionan si miden más de 507904 bytes (512Kbytes-16 kbytes). Esto lo he ido determinando mediante prueba y error tras varias horas de rascarme la cabeza. Por eso es importante decidir qué módulos incluímos y cuáles dejamos fuera.

    Aunque con Lua NodeMCU estemos limitados a un firmware de 496KB, podemos usar el resto de la memoria Flash como un sistema de ficheros simple.

Una vez elegida la versión de Lua (desarrollo o estable) y los módulos que nos interesan, introducimos nuestra dirección de correo electrónico y NodeMCU custom builds nos enviará un email cuando nuestro Firmware Lua esté listo. Lo descargamos a nuestro ordenador y lo enviamos a la placa ESP8266 de NodeMCU de la siguiente manera:

jcea@ubuntu:~/NodeMCU$ esptool.py -p /dev/ttyUSB0 write_flash --verify 0 nodemcu-dev-28-modules-2016-04-09-01-43-10-float.bin
Connecting...
Erasing flash...
Took 2.28s to erase flash block
Writing at 0x0000e000... (11 %)
[...]
Wrote 504832 bytes at 0x00000000 in 53.4 seconds (75.6 kbit/s)...
Leaving...
Verifying just-written flash...
Connecting...
Verifying 0x7b26f (504431) bytes @ 0x00000000 in flash against nodemcu-dev-28-modules-2016-04-09-01-43-10-float.bin...
-- verify OK

La utilidad Python esptool, instalable a través de PYPI, pone la placa NodeMCU en modo programación, envía la versión del Firmware que le indicamos y lo verifica. Obsérvese que no se indica una velocidad específica del puerto serie porque la ROM de programación del ESP8266 incluye una rutina de autodetección de velocidad. Esptool utilizará 115200 bits por segundo, lo máximo habitualmente soportado por un puerto serie.

A continuación nos conectamos a la placa NodeMCU como un puerto serie USB y pulsamos el botón de Reset. Veremos lo siguiente [1]:

[1] Si tienes problemas para interactuar con la placa NodeMCU a 115200 bits por segundo, prueba con 9600bps, la velocidad clásica. Las versiones antiguas del firmware se comunicaban a esa velocidad.
 jcea@ubuntu:~/NodeMCU$ python3 -m serial.tools.miniterm /dev/ttyUSB0 115200
 --- Miniterm on /dev/ttyUSB0  115200,8,N,1 ---
 --- Quit: Ctrl+] | Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H ---
 [...]
 don't use rtc mem data
 [...]
 Self adjust flash size.
 [...]
 NodeMCU custom build by frightanic.com
     branch: dev
     commit: 7d576efed94092916e1a84bccba6319d62b9dedf
     SSL: true
     modules: adc,am2320,bme280,crypto,dht,encoder,file,gpio,http,hx711,i2c,mdns,mqtt,net,node,ow,pwm,rc,rtcfifo,rtcmem,rtctime,sigma_delta,sntp,spi,struct,tmr,uart,wifi
  build  built on: 2016-04-09 01:42
  powered by Lua 5.1.4 on SDK 1.5.1(e67da894)
 lua: cannot open init.lua
 > print "hola mundo"
 hola mundo
 > print(node.flashsize())
 4194304
 > wifi.setmode(wifi.STATION)
 > wifi.eventmon.register(wifi.eventmon.STA_CONNECTED, function(T) print('CONECTADO') end)
 > wifi.eventmon.register(wifi.eventmon.STA_DISCONNECTED, function(T) print('DESCONECTADO') end)
 > wifi.sta.config("Nirvana", "XXXXX")
 > CONECTADO
 > http.get('https://www.jcea.es/', nil, function(code, data) print(code) end)
 > 200

El arranque de Lua nos muestra la versión y qué modulos hemos decidido incluir en la compilación que solicitamos a NodeMCU custom builds. En la línea 16 nos indica que no ha podido encontrar el fichero init.lua. Esto es normal, ahí escribiríamos el código Lua que queremos lanzar automáticamente cuando se arranca la placa NodeMCU. En las líneas 17-18 hacemos el típico Hola Mundo. Las líneas 19-20 confirman que tenemos 4MB de memoria Flash. En las líneas 21-24 configuramos el WIFI del ESP8266 en modo cliente y nos conectamos a mi red doméstica Nirvana, cosa que nos confirma en la línea 25. Obsérvese el uso de callbacks para las notificaciones.

Usamos también callbacks en las conexiones TCP/IP. En la línea 26 hacemos una conexión cifrada [2] a mi web personal e indicamos que queremos ver el código devuelto por el servidor web. En la línea 27 vemos que se trata de un código 200 de "todo ha ido bien".

[2] En el momento de escribir este artículo, usar cifrado supone utilizar el firmware de desarrollo. Más detalles en HTTPS (SSL) get request with NodeMCU.

Por curiosidad, en el log del servidor web veo lo siguiente:

XX.XX.XX.XX - [01/Jun/2016:14:50:55 +0200] "GET / HTTP/1.1" 200 13165 "-" "ESP8266" In: 531 Out: 17198 Time: 5666us mod_deflate: - pct. SSL: TLSv1.1 AES128-SHA HTTP/1.1

Se trata de una conexión TLS 1.1 con cifrado AES 128 y SHA-1. Esperemos que versiones futuras del firmware migren a TLS 1.2 y SHA-256.

Ahora lo que te queda es aprender Lua y leerte con calma la documentación específica de NodeMCU.

Algunos enlaces interesantes:

Advertencia

La memoria Flash del ESP8266 tiene un número limitado de escrituras. No debería ser un problema a la hora de actualizar el firmware de vez en cuando, pero cuidado con utilizar la memoria Flash libre como un sistema de ficheros con mucha actividad de escritura.