An Introduction to the ESP8266
Tags: diy, tutorial, beginners, iot
Published: 2019-03-24 18:11:59

---
title: An Introduction to the ESP8266
published: true
description: A quick guide to uploading NodeMCU firmware and lua source code to the ESP8266 microcontroller
tags: diy, tutorial, beginners, IoT
---

This was originally written on my blog, but I figured it can help save others hours of troubleshooting so I'll share it here as well!

**Disclaimer**: This was written and test on a Debian based Linux system. Commands may vary for Mac, Windows, and other Unix-like machines.

## Toolbox
[esptool](https://github.com/espressif/esptool) - Needed for uploading the initial firmware

[ESPlorer](https://esp8266.ru/esplorer/#download) - Needed for uploading source code

[Firmware](https://nodemcu-build.com/) - Self-explanatory, the link points to the recommended cloud firmware builder for ease of use.

These were chosen because they work cross-platform for the most part. However, additional tools/options can be found [here](https://frightanic.com/iot/tools-ides-nodemcu/).

## Firmware Upload
Assuming you have downloaded your firmware with any additional modules, run the code below to upload it to your microcontroller:

```bash
sudo esptool/esptool.py write_flash -fm qio 0x00000 <nodemcu-firmware>.bin
```

Esptool, depending on your version, will enumerate all available serial ports until it finds a connected device. As such, specifying the serial port should not be necessary in later releases- in theory. 

**Note**: I had to run the command with *sudo* in order to access my serial port (which I hate to do to be honest). If yours works without sudo than feel free to omit.

**Note Note**: This is also assuming you have the esptool.py repository and the firmware in the same project root. Your paths may vary. 

## Testing the ESP8266
Now, run ESPlorer via the following command:
```bash
sudo java -jar ESPlorer/ESPlorer.jar
```
**Note**: Although it launches just fine without sudo, I noticed I still wasn’t able to establish a connection unless I launched it with sudo.

Once it’s launched, set the baud rate, next to the open connection button, to 115200 if it isn't set already (that’s what worked for me to open the connection after extensive troubleshooting and an obscure unresolved github issue). Once that's confirmed, connect your device and open a connection.

Lastly, copy and paste the following sample lua code into ESPlorer as a new file. Replace *mySSID* and *myPassword* with your own network credentials.

```lua
local SSID = "mySSID"
local PASSWORD = "myPassword"
function startup()
    if file.open("init.lua") == nil then
        print("init.lua deleted or renamed")
    else
        print("Running")
        file.close("init.lua")
    end
end

-- Define WiFi station event callbacks 
wifi_connect_event = function(T) 
  print("Connection to AP("..T.SSID..") established!")
  print("Waiting for IP address...")
  if disconnect_ct ~= nil then disconnect_ct = nil end  
end

wifi_got_ip_event = function(T) 
  -- Note: Having an IP address does not mean there is internet access!
  -- Internet connectivity can be determined with net.dns.resolve().    
  print("Wifi connection is ready! IP address is: "..T.IP)
  -- a simple http server
    srv=net.createServer(net.TCP) 
    srv:listen(80,function(conn) 
        conn:on("receive",function(conn,payload) 
            local response = {
            "HTTP/1.0 200 OK\r\nServer: NodeMCU on ESP8266\r\nContent-Type: text/html\r\n\r\n",
            "<html><body>Hello world, come here often?</body></html"
            }
            print(payload)

              -- sends and removes the first element from the 'response' table
            local function send(localSocket)
                if #response > 0 then
                    localSocket:send(table.remove(response, 1))
                else
                    localSocket:close()
                    response = nil
                end
            end

            -- triggers the send() function again once the first chunk of data was sent
            conn:on("sent", send)
            send(conn)

            -- conn:send(response)
        end) 
    end)
--   print("Startup will resume momentarily, you have 3 seconds to abort.")
--   print("Waiting...") 
  tmr.create():alarm(3000, tmr.ALARM_SINGLE, startup)
end

wifi_disconnect_event = function(T)
  if T.reason == wifi.eventmon.reason.ASSOC_LEAVE then 
    --the station has disassociated from a previously connected AP
    return 
  end
  -- total_tries: how many times the station will attempt to connect to the AP. Should consider AP reboot duration.
  local total_tries = 75
  print("\nWiFi connection to AP("..T.SSID..") has failed!")

  --There are many possible disconnect reasons, the following iterates through 
  --the list and returns the string corresponding to the disconnect reason.
  for key,val in pairs(wifi.eventmon.reason) do
    if val == T.reason then
      print("Disconnect reason: "..val.."("..key..")")
      break
    end
  end

  if disconnect_ct == nil then 
    disconnect_ct = 1 
  else
    disconnect_ct = disconnect_ct + 1 
  end
  if disconnect_ct < total_tries then  
    print("Retrying connection...(attempt "..(disconnect_ct+1).." of "..total_tries..")")
  else
    wifi.sta.disconnect()
    print("Aborting connection to AP!")
    disconnect_ct = nil  
  end
end

-- Register WiFi Station event callbacks
wifi.eventmon.register(wifi.eventmon.STA_CONNECTED, wifi_connect_event)
wifi.eventmon.register(wifi.eventmon.STA_GOT_IP, wifi_got_ip_event)
wifi.eventmon.register(wifi.eventmon.STA_DISCONNECTED, wifi_disconnect_event)

print("Connecting to WiFi access point...")
wifi.setmode(wifi.STATION)
wifi.sta.config({ssid=SSID, pwd=PASSWORD})
```

If you aren't familiar with lua, don't worry, I wasn't either- a lot of it is still trial and error. But experience is the best teacher so don't let that stop you! In short, the code above sets up a wifi station with our own custom event callbacks for when the device connects to the network specified, when it receives an ip address, and when it disconnects for whatever reason.

Once it receives an ip address, it sets up an http server where it will listen for any inbound connections on port 80 and return a simple message

When we finally click the *Save as Init* button and then the *Save to ESP* button, ESPlorer will upload the file and try to run it (you may have to hit the little reset button on the actual device if the button's are greyed out as that means a connection has not been fully established yet). Now, once it connects and gets and ip address go to *http://ipaddress* from a device on the same network to see if we can successfully connect to the device.

![success](https://bcvii.com/static/a13093b04879d993a4e7d5d0c4a53b49/56de2/success.png)

**Success! :)**
## Conclusion
We did it team! Now we can play with the code and use it as a baseline for your next project. For example I’m using it to interact with GPIO pins and control my robots via wifi, and since I fried my first microcontroller trying to connect it to stepper motors, that'll probably be the next guide to save someone else the frustration. Regardless, the possibilities are near endless with the available firmware modules. What are you building with yours?

Feel free to ask any questions if anything needs clarifying! The modules [documentation](https://nodemcu.readthedocs.io/en/master/) is definitely a useful resource as well. :)