Kazu's Log

Jan 16, 2016

Blinking an LED with NodeMCU

What I did first on NodeMCU was connecting to the Internet, but usually blinking an LED is the “hello world” in the microcontroller world. So let’s do it.

Connecting an LED


  • Node MCU Developer Kit
  • LED
  • Resistor

The circuit is pretty simple.

  • Connect the Node MCU’s D1 (GPIO) to the LED’s longer lead (anode)
  • Connect the LED’s shorter lead (cathode) to the resistor
  • Connect the resistor to the Node MCU’s GND


luatool is a small Python script that communicates with NodeMCU. Instead of using pySerial’s miniterm.py interactively, you can use luatool to upload your Lua script to the device.

luatool needs pySerial. The install instruction is in my previous post.

% git clone https://github.com/4refr0nt/luatool
% cd luatool
% python luatool/luatool.py --port /dev/cu.SLAB_USBtoUART --id

->=node.chipid() -> send without check

Why using infinite loops is a bad idea?

Once you have luatool, you can write a Lua script on Emacs (or your favorite editor, but isn’t it Emacs?) and upload the script to the device.

To blink an LED, the simplest solution is just having an infinite loop like below.

US_TO_MS = 1000

gpio.mode(LED_PIN, gpio.OUTPUT)

while true do
   gpio.write(LED_PIN, gpio.HIGH)
   tmr.delay(500 * US_TO_MS)
   gpio.write(LED_PIN, gpio.LOW)
   tmr.delay(500 * US_TO_MS)

Sending the script by using luatool…

% python luatool/luatool.py --port /dev/cu.SLAB_USBtoUART --src ~/blink.lua --dofile
->dofile("blink.lua") -> send without check
--->>> All done <<<---

It does work, but then you will realize that you can’t upload anything from luatool.

The reason is, luatool is doing all operations by just sending Lua code. Once you execute a script that has an infinite loop, The Lua interpreter on the device can’t receive any new code due to the loop, and it makes luatool unusable.

Use tmr.alarm instead

Actually NodeMCU’s reference clearly metiones that on tmr.delay’s section.

Busyloops the processor for a specified number of microseconds.

This is in general a bad idea, because nothing else gets to run, and the networking stack (and other things) can fall over as a result.

Instead you can use tmr.alarm that wraps tmr.register and tmr.start.

Here is the new script. EXPR and A or B is Lua’s ternary operator equivalent idiom.


gpio.mode(LED_PIN, gpio.OUTPUT)
value = true

tmr.alarm(0, 500, 1, function ()
    gpio.write(LED_PIN, value and gpio.HIGH or gpio.LOW)
    value = not value

If your previous script is running, you need kill that by clicking RST (Reset) on the device, before using luatool.

% python luatool/luatool.py --port /dev/cu.SLAB_USBtoUART --src ~/blink.lua --dofile
->dofile("blink.lua") -> send without check
--->>> All done <<<---

It looks same, but unlike before, you can use luatool even this script is running.