Month: January 2016

stdin:1: ‘)’ expected near ‘]’

I have had some problems while coding my NodeMCU in LUA in that I ran into problems during the upload giving me error messages like

stdin:1: ')' expected near ']'

or

stdin:1: ')' expected near '='

This is before execution so it seems that even during the upload there is some checking. What I’ve found so far is that the following does not work:

a = b[d]

During upload you can then get this error, however… if you put a space after the close square bracket (before the next line), you do not get the error. I also found that the following gives an error:

a = b[c[d]]

where it does not matter what the variable names are and d can even be a string. Just the fact that there are two square brackets after each other gives the error. In this case, it is not enough to put a space at the end of the line. You also need to put a space between the two close square brackets.

 

Advertisements
Infinite loop on NodeMCU

Infinite loop on NodeMCU

Yes, it is possible to create an infinite loop on the NodeMCU. It is actually quite simple….

Of course, all over the internet there are helpful people who tell you how not to get in an infinite loop and why you shouldn’t have done what you did but you don’t really look for what to do with an infinite loop on your NodeMCU on the internet until you have need to get out of it.

You guessed it, I managed to get myself into an infinite loop but I also managed to get myself out of it.

Initially I thought it would be simple, I would just clear the memory of my NodeMCU and start again. I have all the code on my computer, so no issue. Unfortunately, even though the NodeMCU is not the fasted device out there, it is apparently fast enough to prevent you from formatting, deleting init.lua or the likes before doing a hard reset and starting from the top.

Well, no worries. Just reflash the thing and be done with it. I did the following to get me into the flash mode:

  • Disconnect LUA Loader or whatever IDE you use
  • Start NodeMCU Flasher and select the correct COM port
  • Connect GPIO01 to ground (should be enough but wasn’t for me. The red light did turn on)
  • Press and hold the flash button
  • Press and release the reset button
  • Press Flash on the NodeMCU Flasher, wait for it to start and than release the flash button

Initially I just reflashed the NodeMCU.bin file but that was not enough. After I reset my NodeMCU it cheerfully continued it’s infinite loop. I needed to do something more brutal to it.

So following the instructions above again but this time, you don’t stop after you flash your NodeMCU.bin on it……

  • Wait for the default file to be done
  • Select the config tab and select or type in the file
    INTERNAL://BLANK
  • Select address 0x00000 and go to operation and click Flash. This will be done quickly
  • Now select every address in the dropdown list and flash the blank file in the position
  • For me there were 4 addresses that did not finish flashing
    • 0x7C000
    • 0x7E000
    • 0xFFC000
    • oxFFE000
  • After you’re done, connect GPIO01 to high and press reset
  • Connect LUA Loader and it should do nothing ūüôā
  • Disconnect LUA Loader
  • Connect GPIO01 to ground
  • In NodeMCU Flasher, select the bin file you want, select address 0x00000
  • Press and hold the flash button
  • Press and release the reset button
  • Press Flash on the NodeMCU Flasher, wait for it to start and than release the flash button
  • Connect LUA Loader
  • Click format or enter file.format()
  • Ready!

This might be serious overkill to get the job done but it worked and I don’t plan to have these quite often anyway.

There are plenty of tips out there to prevent this from happening. I will update my init.lua and share it in one of my next posts. The clue is to either start the real program with a timer which you can stop (tmr.stop(0)) or some other mechanism to prevent the program from running). I already had such a feature in my init.lua but I was working on a multiple wifi network selector which runs before my first check of my interrupt and that caused the infinite loop.

NodeMCU & KY-015 temperature sensor

NodeMCU & KY-015 temperature sensor

Trying to get the KY-015 temperature sensor, part of the 37 sensors set, also known as a DHT11 sensor, working on the NodeMCU with LUA turned out to be quite a challenge.

The DHT11 sensor, a cominbation of a temperature and humidity sensor, uses what is known as a 1-wire system, 3 pins, ground, vcc and signal and by placing signals on the signal wire and than listening, data can be received from from the sensor. Timing is essential with this and that turned out to be the challenge. There is a lot of code available on the internet for the Arduino, but the ESP8266 is a lot slower. There is also some sample code available for the NodeMCU in LUA but none of these worked. Eventually I recombined some sample codes, tweaked it and had working code. With that said, until I have more experience with these 1-wire systems, the code is provided as-is.

The code consists of two parts, a module and a program to use the module.

The module (which I have called dhtxx.lua because the libary should also work for the DHT22):

--------------------------------
--                            --
--  dhtxx module for NodeMCU  --
--                            --
--------------------------------

local moduleName = ...
local M = {}
_G[moduleName] = M

local temp = 0
local hum = 0
local bitStream = {}

function M.init(pin)
  bitStream = {}
  for j = 1, 40, 1 do
    bitStream[j] = 0
  end
  bitlength = 0

  gpio.mode(pin,gpio.OUTPUT)
  gpio.write(pin,gpio.LOW)
  tmr.delay(20000)
  --Use Markus Gritsch trick to speed up read/write on GPIO
  gpio_read = gpio.read
  gpio_write = gpio.write

  gpio.mode(pin, gpio.INPUT)

  while (gpio_read(pin) == 0) do end

  c = 0
  while (gpio_read(pin) == 1 and c < 100) do c = c + 1 end

  while (gpio_read(pin) == 0) do end

  c = 0
  while (gpio_read(pin) == 1 and c < 100) do c = c + 1 end

  for j = 1, 40, 1 do
    while (gpio_read(pin) == 1 and bitlength < 10) do       bitlength = bitlength + 1     end     bitStream[j] = bitlength     bitlength = 0     while (gpio_read(pin) == 0) do end   end   hum = 0   temp = 0   for i = 1, 8, 1 do     if (bitStream[i + 0] > 2) then
      hum = hum + 2 ^ (8 - i)
    end
  end
  for i = 1, 8, 1 do
    if (bitStream[i + 16] > 2) then
      temp = temp + 2 ^ (8 - i)
    end
  end

  local byte_0 = 0
  local byte_1 = 0
  local byte_2 = 0
  local byte_3 = 0
  local byte_4 = 0

  for i = 1, 8, 1 do -- Byte 0
    if (bitStream[i] > 2) then
      byte_0 = byte_0 + 2 ^ (8 - i)
    end
  end

  for i = 1, 8, 1 do -- Byte 1
    if (bitStream[i+8] > 2) then
      byte_1 = byte_1 + 2 ^ (8 - i)
    end
  end

  for i = 1, 8, 1 do -- Byte 2
    if (bitStream[i+16] > 2) then
      byte_2 = byte_2 + 2 ^ (8 - i)
    end
  end

  for i = 1, 8, 1 do -- Byte 3
    if (bitStream[i+24] > 2) then
      byte_2 = byte_2 + 2 ^ (8 - i)
    end
  end

  for i = 1, 8, 1 do -- Byte 4
    if (bitStream[i+32] > 2) then
      byte_4 = byte_4 + 2 ^ (8 - i)
    end
  end

  if byte_1==0 and byte_3 == 0 then
    byte_5 = byte_0+byte_2
    if(byte_4 ~= byte_5) then
      hum = nil
      temp = nil
    else
      hum = byte_0 *10
      temp = byte_2 *10 
    end

  else
    hum = byte_0 * 256 + byte_1
    temp = byte_2 * 256 + byte_3
    checksum = byte_4

    checksumTest = (bit.band(hum, 0xFF) + bit.rshift(hum, 8) + bit.band(temp, 0xFF) + bit.rshift(temp, 8))
    checksumTest = bit.band(checksumTest, 0xFF)

    if temp > 0x8000 then
      temp = -(temp - 0x8000)
    end

    if (checksumTest - checksum >= 1) or (checksum - checksumTest >= 1) then
      hum = nil
    end

  end

  bitStream = {}
  gpio_read = nil
  gpio_write = nil
end

function M.getTemp()
  return temp
end

function M.getHumidity()
  return hum
end

return M

and the program to use the module:

dht = require("dhtxx")

dhtpin = 3
dht.init(dhtpin)

t = dht.getTemp()
h = dht.getHumidity()

if h == nil then
  print("Error reading from dhtxx")
else
  print(string.format("Temperature: %.1f deg C",t/10))
  print(string.format("Humidity: %.1f%%",h/10))
end
dht = nil
package.loaded["dhtxx"] = nil
Triggered action on NodeMCU

Triggered action on NodeMCU

Sometimes you want to react on an event, some change on your GPIOs, and when that happens do something. LUA for NodeMCU has something for just that, gpio.trig and that’s what I will be using in my next example.

For this setup, I have two leds on ports 2 and 4 and I have a switch on port 1 which is my trigger event. What I want is that when I press the switch, led on port 2 goes on for half a second, than led on port 3 for half a second and then post a trigger on IFTTT.

The code:

--------------------
--                --
--  gpiotrig.lua  --
--                --
--------------------

-- 1:set variables and initial GPIO states
led1 = 2
led2 = 4
monitor = 1
gpio.mode(led1,gpio.OUTPUT)
gpio.mode(led2,gpio.OUTPUT)
gpio.write(led1,gpio.LOW)
gpio.write(led2,gpio.LOW)
lastlevel = 1

-- 2:function to send IFTTT trigger
function ifttt (code, value2,value3)
  conn = net.createConnection(net.TCP, false)
  conn:on("receive", function(conn, answer) print(answer) end)
  conn:on("connection", function(cn, answer)
    cn:send("GET /trigger/"..code.."/with/key/U3Zqpx4Oo-Z0lLFzfvh2D?"
    .."value1="..thisNode
    .."&value2="..value2.."&value3="..value3.." HTTP/1.1\r\n"
    .."Host: maker.ifttt.com\r\n"
    .."Connection: keep-alive\r\n"
    .."Accept: */*\r\n\r\n")
  end)
  conn:connect(80,"maker.ifttt.com")
end

-- 3:function to turn led 2 off
function led2off ()
  gpio.write(led2,gpio.LOW)
  ifttt("GPIO",monitor,lastlevel)
end

-- 4:function to turn led 1 off, led 2 on, timer for led 2 off
function ledswitch ()
  gpio.write(led1,gpio.LOW)
  gpio.write(led2,gpio.HIGH)
  tmr.alarm(1,500,0,led2off)
end

-- 5:function to turn led 1 on, timer for next step
function ledtrig ()
  gpio.write(led1,gpio.HIGH)
  lastlevel = level
  tmr.alarm(1,500,0,ledswitch)
end

-- 6:prepare the trigger
gpio.mode(monitor,gpio.INPUT)
gpio.trig(monitor,"down",ledtrig)

Section 1: define which GPIOs contain the leds and which GPIO contains the trigger. Set the GPIO modes correctly and turn off the leds.
Sections 2 to 5 contain the functions and section 6 initiates the trigger monitor.

There are different functions because each is triggered by a timer. In section 6 we initiate the trigger for port monitor which is triggered at a falling edge. There are more options which you can read about here. The function ledtrig is called. Remember to set the port to input before you define the trigger.

Section 5 contains function ledtrig which turns on led 1, save the level of the GPIO (not really necessary since it is a 0 or 1 and we trigger on the falling edge so we know) and start a timer for the next function, ledswitch, in 0.5 seconds.

Section 4 shows function ledswitch which turns off led 1, turns on led 2 and starts the timer for the third function, led2off.

Section 3 has function led2off which turns off led 2 and calls function ifttt with information GPIO, the port monitored and the saved level.

Finally in section 2 we have the ifttt function which does a RESTful get at ifttt.com. Note that we use the value thisNode which I set in the init.lua to show which NodeMCU is sending the trigger.

The program works nicely but does not have any error handling nor does it catch it if you press the switch for example while the previous trigger is still running. If you want your NodeMCU to run autonomously, you should definitely include some error handling and possibly alerting.

HTTP server on NodeMCU

HTTP server on NodeMCU

To interact with our NodeMCU, we could use an HTTP server. The Hello world version of this is quite simple:

srv = net.createServer(net.TCP)
srv:listen(80,function(conn) 
  conn:on("receive",function(cn,request) 
    print(request) 
    cn:send("Hello world")
    cn:close();
    collectgarbage();
  end) 
end)

Upload and to your NodeMCU and execute it. If you now go to the IP of your NodeMCU, you should see Hello world.
The code is relatively straight forward. You create a TCP server which listens on port 80

If you want to try different things with your code and you execute it again, you will get the error message only one tcp server allowed if you have not restarted the NodeMCU since the last time you executed the code. Instead of restarting, executing the following:

srv:close()

This will stop the current server and you can execute your file again to restart it. Since LUA on the NodeMCU keeps variables even after the program has stopped we can create a more resilient version this way:

----------------------
--                  --
--  httpserver.lua  --
--                  --
----------------------

-- check whether server is already started
if srv~=nil then
  srv:close()
end

-- create webserver
srv = net.createServer(net.TCP)
srv:listen(80,function(conn)
  conn:on("receive",function(cn,request)
    print(request)

    -- the webpage
    cn:send("Hello world")
    cn:close()
    collectgarbage()
  end) 
end)

Next step, actually interact with the NodeMCU. For this we need to be able to send it requests of some sort. For testing I connected two leds to the NodeMCU, port 2 and port 3. I want to use the webserver to control the leds. Let’s first post the code which I will explain below it:

-----------------------
--                   --
--  httpserver2.lua  --
--                   --
-----------------------

-- 1:set variables and initial GPIO states
led1 = 2
led2 = 3
gpio.mode(led1,gpio.OUTPUT)
gpio.mode(led2,gpio.OUTPUT)
gpio.write(led1,gpio.LOW)
gpio.write(led2,gpio.LOW)

-- 2:check whether server is already started
if srv~=nil then
  srv:close()
end

-- 3:create webserver
srv = net.createServer(net.TCP)
srv:listen(80,function(conn)
  conn:on("receive",function(cn,request)
    local buf = ""

    -- 4:extra path and variables
    local _,_,method,path,vars = string.find(request,"([A-Z]+) (.+)?(.+) HTTP")
    if(method==nil) then
      _, _, method, path = string.find(request,"([A-Z]+) (.+) HTTP")
    end

    -- 5:extract the variables passed in the url
    local _GET = {}
    if (vars~=nil) then
      for k,v in string.gmatch(vars,"(%w+)=(%w+)&*") do
        _GET[k] = v
      end
    end

    -- 6:the webpage
    buf = buf.."

Demo server

” ¬†¬†¬† buf = buf..”Led 1 Turn on¬†” ¬†¬†¬† buf = buf..”Turn off
” ¬†¬†¬† buf = buf..”Led 2 Turn on¬†” ¬†¬†¬† buf = buf..”Turn off
” ¬†¬†¬† — 7:the actions ¬†¬†¬† if (_GET.pin==”L1On”) then ¬†¬†¬†¬†¬† gpio.write(led1,gpio.HIGH) ¬†¬†¬† elseif (_GET.pin==”L1Off”) then ¬†¬†¬†¬†¬† gpio.write(led1,gpio.LOW) ¬†¬†¬† elseif (_GET.pin==”L2On”) then ¬†¬†¬†¬†¬† gpio.write(led2,gpio.HIGH) ¬†¬†¬† elseif (_GET.pin==”L2Off”) then ¬†¬†¬†¬†¬† gpio.write(led2,gpio.LOW) ¬†¬†¬† end — 8:send the data and close the connection ¬†¬†¬† cn:send(buf) ¬†¬†¬† cn:close() ¬†¬†¬† collectgarbage() ¬† end) end)

Section 1 is straight forward, set variables for the ports of led 1 and 2 and turn off both leds.
In section 2 we close the current server if it is started to be followed by section 3 where the new http server is created, both described above.

Section 4 is where we take the request information send by the user and using pattern matching, extract the path and the variables (if any). In section 5 we put the variables in a LUA table, again using pattern matching.

Section 6 is the webpage. In this case we did not check the path variable. Regardless of what page you request, you will always get the same page.

Finally, section 7 is where we perform the GPIO actions based on the request and section 8 is where the data is send to the user and the connection is closed.

Wait for IP on NodeMCU

So, now that the NodeMCU is trying to connect to the wifi, we know how to do a RESTful call, it’s time for the last step, waiting for the NodeMCU to connect and get a valid IP.

The code:

-- wait for an IP
cnt = 10
tmr.alarm(0,500,1,function()
  if wifi.sta.getip()==nil then
    cnt = cnt-1
    if cnt<=0 then

      -- Did not get an IP in time, so quitting
      tmr.stop(0)
      gpio.write(pin_error,1)
      print "Not connected to wifi."
    end
  else

    -- Connected to the wifi
    tmr.stop(0)
    print("\nStarting main")
    dofile("main.lua")
  end
end)

The code uses a timer to check every 500 microseconds (half a second) to see whether we have a valid IP address. If we do we can start our main program. If we don’t we continue to try, but at most 10 times (the cnt variable). If still fails after 10 attempts (5 seconds), we assume it will not connect. We turn on our error led and stop the timer.

Well, lets now put it all together into one beautiful init.lua which we can use on any of our NodeMCU’s.

------------------
--              --
--   init.lua   --
--              --
------------------

-- 1:the wifi credentials. Change to match your wifi
ssid = "YourSSID"
pass = "YourPass"
thisNode = 1

-- 2:Configure wifi
wifi.setmode(wifi.STATION)
print("\nMy MAC address: "..wifi.sta.getmac())
wifi.sta.config(ssid,pass)

-- 3:Prepare GPIOs
pin_interrupt = 1
gpio.mode(pin_interrupt,gpio.INPUT)
pin_error = 0
gpio.mode(pin_error,gpio.OUTPUT)

-- 4:Read and write GPIOs
gpio.write(pin_error,gpio.HIGH)
interruptit = gpio.read(pin_interrupt)

-- 5:Check whether to start the main program
if interruptit==1 then

  -- 6:Wait for an IP
  cnt = 10
  tmr.alarm(0,500,1,function()
    interruptit = gpio.read(pin_interrupt)
    if interruptit==0 then

      -- 7:The interrupt button was pressed while waiting for an IP
      tmr.stop(0)
      gpio.write(pin_error,gpio.LOW)
      print "GPIO1 low, so not starting main"
    else
      if wifi.sta.getip()==nil then
        cnt = cnt-1
        if cnt<=0 then

          -- 8:Did not get an IP in time, so quitting
          tmr.stop(0)
          gpio.write(pin_error,gpio.LOW)
          print "Not connected to wifi."
        end
      else

        -- 9:Connected to the wifi, send IFTTT trigger
        tmr.stop(0)
        ip, nm, gw = wifi.sta.getip()
        conn = net.createConnection(net.TCP, false) 
        conn:on("receive", function(conn, answer) print(answer) end)
        conn:on("connection", function(cn, answer)
          cn:send("GET /trigger/NodeMCUBoot/with/key/--YourKey--?"
          .."value1="..thisNode.."&value2="..ip.." HTTP/1.1\r\n"
          .."Host: maker.ifttt.com\r\n"
          .."Connection: keep-alive\r\n"
          .."Accept: */*\r\n\r\n")
        end)
        conn:connect(80,"maker.ifttt.com")

        -- 10:Start the main program
        print("\nStarting main")
        dofile("main.lua")
      end
    end
  end)

else

  -- 11:The interrupt button was pressed
  gpio.write(pin_error,gpio.LOW)
  print("\nGPIO1 low, so not starting main.")
end

That’s it, all combined.

So we connect to the wifi, we set and check the GPIOs, we wait for an IP (while still checking if the switch on GPIO1 is pressed) and once we have an IP, we send a trigger to IFTTT to show that we are up and running and start the main program.

HTTP GET on the NodeMCU

HTTP GET on the NodeMCU

Well, after toying with it and getting it to work, I wanted it to be able to do something, obviously, and one of the first things I wanted it to do is to be able to grab a webpage and if that works, get it to do some sort of Web API or RESTful call.

The code for getting a webpage turned out to be relatively simple:

conn = net.createConnection(net.TCP, false) 
conn:on("receive", function(conn, answer) print(answer) end)
conn:connect(80,"23.23.215.91")
conn:send("GET / HTTP/1.1\r\n"
  .."Host: maker.ifttt.com\r\n"
  .."Connection: keep-alive\r\nAccept: */*\r\n\r\n")

This is simple if you know the IP. However if you want to connect to a domain (which of course makes much more sense) the code becomes a little more complex because the NodeMCU has to do a DNS lookup and only after it has done that should you send the GET etc strings so these should only be send after a successful connection (thanks to a fellow blogger who wrote on this). This gives the following code:

conn = net.createConnection(net.TCP, false) 
conn:on("receive", function(conn, answer) print(answer) end)
conn:on("connection", function(cn, answer)
  cn:send("GET / HTTP/1.1\r\n"
  .."Host: maker.ifttt.com\r\n"
  .."Connection: keep-alive\r\nAccept: */*\r\n\r\n")
end)
conn:connect(80,"maker.ifttt.com")

Well, now that we can grab a webpage, the next step will be to do some sort of RESTful call which is quite simple. So let’s jump ahead and make it a little more complex. I want to do a RESTful call to IFTTT, more specifically the Maker channel which is created specifically for IoT (internet of things) type devices.

(If you are not familiar with IFTTT, you should visit their website. In short, it’s a web utility that allows you to create conditional things to happen, IF This Than That).

I will be using a IFTTT recipe to send a message to Pushover which will send a message to my phone.

ip, nm, gw = wifi.sta.getip()
thisNode = 1
conn = net.createConnection(net.TCP, false) 
conn:on("receive", function(conn, answer) print(answer) end)
conn:on("connection", function(cn, answer)
  cn:send("GET /trigger/NodeMCUBoot/with/key/--yourkey--?"
  .."value1="..thisNode.."&value2="..ip.." HTTP/1.1\r\n"
  .."Host: maker.ifttt.com\r\n"
  .."Connection: keep-alive\r\n"
  .."Accept: */*\r\n\r\n")
end)
conn:connect(80,"maker.ifttt.com")

Now whenever this code is executed, I get a pushover message saying
IFTTT: Maker: NodeMCU 1 is alive and has IP 10.1.2.3

This of course will be integrated in my init.lua so that whenever a NodeMCU is booted, I get a message, to not only tell me it’s alive, but also what it’s IP is. In one of my next posts I will explain on how to wait for an assigned IP and than combine everything init.lua.

NodeMCU and separate USB adapter

NodeMCU and separate USB adapter

I wanted to work with the NodeMCU while travelling or some place where I could sit with my laptop without having a power supply handy for the powered USB hub, like on the couch so I decided to give the USB to serial adapter another try. After connecting it I found that the NodeMCU can actually be powered through the adapter by just using my laptop.

Connecting is quite straight forward. My adapter has 6 pins of which I am using 4.

  • 3v3 of the adapter is connected to 3v3 of the NodeMCU
  • GND of the adapter is connected to GND of the NodeMCU
  • TXD of the adapter is connected to RX of the NodeMCU
  • RXD of the adapter is connected to TX of the NodeMCU

That’s it. Connect the USB cable from the adapter to your computer (and remember to disconnect the other one) and you should be able to connect to your NodeMCU without a powered USB hub.

(The led in the picture is the led I described in my previous post)

GPIO output on the NodeMCU

GPIO output on the NodeMCU

Next step, let’s send output to a GPIO pin. In this post, let’s keep it simple. Let’s connect a led to GPIO0 (D0 on the board) and turn it on and off. To test this yourself, connect a led, the cathode of the led to ground and the anode to GPIO0. If you are struggling with which is which, check these instructions.

gpio.mode(0,gpio.OUTPUT)
gpio.write(0,gpio.LOW)

Well, that was simple enough. We have connected a led and turned it off. Turning it on is just as simple:

gpio.write(0,gpio.HIGH)

As you have guessed, the first line sets the mode of the GPIO to output (instead of input as shown in my earlier post on this). The second line sets GPIO 0 (the first parameter) to 0 (second parameter).

This is too simple, so let’s start making it a little more complex by creating a neat init.lua which allows you to stop it. Remember that after you are done, your NodeMCU will be ‘in the field’ and you will not have a terminal attached. I have created the following init.lua which will automatically connect if a GPIO pin is not low.

The setup:

  • a GPIO configured with a switch or button to allow for an interrupt
    (remember you cannot use GPIO0 for this because if this is connected to ground, your NodeMCU will expect a new firmware)
    In my example, GPIO 1
  • a GPIO configured with a led where the cathode is connect to ground and the anode to a GPIO or you can use the on board led which is connected to GPIO0. That’s what I did in this example. A low signal on GPIO0 will turn on the red led.

My init.lua:

------------------
--              --
--   init.lua   --
--              --
------------------

-- 1:The wifi credentials. Change to match your wifi
ssid = "YourSSID"
pass = "YourPassword"

-- 2:Configure wifi
wifi.setmode(wifi.STATION)
print("\nMy MAC address: "..wifi.sta.getmac())
wifi.sta.config(ssid,pass)

-- 3:Prepare GPIOs
pin_interrupt = 1
gpio.mode(pin_interrupt,gpio.INPUT)
pin_error = 0
gpio.mode(pin_error,gpio.OUTPUT)

-- 4:Read and write GPIOs
gpio.write(pin_error,gpio.HIGH)
interruptit = gpio.read(pin_interrupt)

-- 5:Check whether to start the main program
if interruptit==1 then
  print("\nStarting main")
  dofile("main.lua")
else
  gpio.write(pin_error,gpio.LOW)
  print("\nGPIO1 low, so not starting main")
end

The first section is the config section with your wifi credentials. The second section connects your NodeMCU to your wifi which I described in earlier posts.

The third section sets the variables and prepares the GPIOs. So pin_interrupt is the GPIO I use to interrupt the booting of the NodeMCU. I use pin_error as the GPIO to show with a led whether there is an error. The idea is that if the code is not running (or some other error which I will handle in a next post) the led is on. So no lights means it is working. This is with the led connected to GPIO0. If you want to use your own led you have to switch HIGH to LOW and vice versa when writing to pin_error.

The fourth section, I read my input and turn off the led. In the last section I check whether the main program needs to start and if not, turn on the led so I can see that the program is not running.

The file main.lua will contain the actual ‘program’ that the NodeMCU needs to do.