Go to file
Nick Andrew 20bca021af README: More work on the build options
List the latest set of modules in the example on disabling modules.

Show which file to edit to tag your firmware to identify it on boot.

Signed-off-by: Nick Andrew <nick@nick-andrew.net>
2015-11-17 00:49:41 +11:00
.settings add spi, and some minor fix 2015-01-18 11:46:15 +08:00
app Merge pull request #750 from lukaszo/coap-deb 2015-11-12 10:41:37 +11:00
bin Removed old SDK-provided bin files. 2015-10-12 13:26:04 +11:00
examples Merge branch 'master' into dev 2015-04-06 00:06:08 +08:00
ld Fix to do TCP port number randomization at boot. 2015-11-05 14:40:57 +11:00
lua_examples ensure backwards compatibility of exising api functions 2015-10-18 11:13:57 +02:00
lua_modules adding lua_module for Grove Digital Light Sensor (http://www.seeedstudio.com/wiki/Grove_-_Digital_Light_Sensor) 2015-07-21 18:56:29 +02:00
pre_build Merge branch 'dev' of https://github.com/nodemcu/nodemcu-firmware 2015-03-16 01:13:03 +08:00
sdk Upgraded LWIP to 1.4.0 released from Espressif. 2015-10-12 14:31:04 +11:00
sdk-overrides/include Override the c_types.h to get int64_t defined properly. 2015-10-12 13:26:04 +11:00
tools Minor tweaks to luac.cross for SDK 1.4 support 2015-11-03 22:45:43 +00:00
.cproject move eclipse project file to root, now eclipse can see all files 2015-01-12 21:04:43 +08:00
.project move eclipse project file to root, now eclipse can see all files 2015-01-12 21:04:43 +08:00
.travis.yml Switch to Travis containerized builds 2015-10-12 13:26:05 +11:00
CONTRIBUTING.md Add @TerryE's comment about announcing work on a PR 2015-11-09 00:28:56 +01:00
LICENSE update doc 2014-11-21 00:10:01 +08:00
Makefile Further cleanup of ld directory. 2015-10-12 13:26:04 +11:00
README.md README: More work on the build options 2015-11-17 00:49:41 +11:00

README.md

NodeMCU 1.4.0

Join the chat at https://gitter.im/nodemcu/nodemcu-firmware Build Status Download

###A lua based firmware for wifi-soc esp8266 Build on ESP8266 sdk 1.4.0
Lua core based on eLua project
cjson based on lua-cjson
File system based on spiffs
Open source development kit for NodeMCU nodemcu-devkit
Flash tool for NodeMCU nodemcu-flasher

Developer Wiki: (https://github.com/nodemcu/nodemcu-firmware/wiki)
api: NodeMCU api
home: nodemcu.com
bbs: Chinese BBS
docs: NodeMCU docs
Tencent QQ group: 309957875

Summary

  • Easy to access wireless router
  • Based on Lua 5.1.4 (without debug, os module.)
  • Event-driven programming preferred
  • Built-in modules: json, file, timer, pwm, i2c, spi, 1-wire, net, mqtt, coap, gpio, wifi, adc, uart and system api.
  • GPIO pins re-mapped: use the index to access gpio, i2c, pwm.
  • Both Integer (less memory usage) and Float version firmware provided.

To Do List (pull requests are very welcome)

  • loadable c module
  • fix wifi smart connect
  • add spi module (done)
  • add mqtt module (done)
  • add coap module (done)
  • cross compiler (done)

Programming Examples

Because Lua is a high level language and several modules are built into the firmware, you can very easily program your ESP8266. Here are some examples!

Connect to your AP

    ip = wifi.sta.getip()
    print(ip)
    --nil
    wifi.setmode(wifi.STATION)
    wifi.sta.config("SSID","password")
    ip = wifi.sta.getip()
    print(ip)
    --192.168.18.110

Manipulate hardware like an Arduino

    pin = 1
    gpio.mode(pin,gpio.OUTPUT)
    gpio.write(pin,gpio.HIGH)
    print(gpio.read(pin))

Write a network application in Node.js style

    -- A simple http client
    conn=net.createConnection(net.TCP, 0)
    conn:on("receive", function(conn, payload) print(payload) end )
    conn:connect(80,"115.239.210.27")
    conn:send("GET / HTTP/1.1\r\nHost: www.baidu.com\r\n"
        .."Connection: keep-alive\r\nAccept: */*\r\n\r\n")

Or a simple HTTP server

    -- A simple http server
    srv=net.createServer(net.TCP)
    srv:listen(80,function(conn)
      conn:on("receive",function(conn,payload)
        print(payload)
        conn:send("<h1> Hello, NodeMcu.</h1>")
      end)
      conn:on("sent",function(conn) conn:close() end)
    end)

Connect to MQTT broker

-- init mqtt client with keepalive timer 120sec
m = mqtt.Client("clientid", 120, "user", "password")

-- setup Last Will and Testament (optional)
-- Broker will publish a message with qos = 0, retain = 0, data = "offline"
-- to topic "/lwt" if client don't send keepalive packet
m:lwt("/lwt", "offline", 0, 0)

m:on("connect", function(con) print ("connected") end)
m:on("offline", function(con) print ("offline") end)

-- on publish message receive event
m:on("message", function(conn, topic, data)
  print(topic .. ":" )
  if data ~= nil then
    print(data)
  end
end)

-- m:connect( host, port, secure, auto_reconnect, function(client) )
-- for secure: m:connect("192.168.11.118", 1880, 1, 0)
-- for auto-reconnect: m:connect("192.168.11.118", 1880, 0, 1)
m:connect("192.168.11.118", 1880, 0, 0, function(conn) print("connected") end)

-- subscribe topic with qos = 0
m:subscribe("/topic",0, function(conn) print("subscribe success") end)
-- or subscribe multiple topic (topic/0, qos = 0; topic/1, qos = 1; topic2 , qos = 2)
-- m:subscribe({["topic/0"]=0,["topic/1"]=1,topic2=2}, function(conn) print("subscribe success") end)
-- publish a message with data = hello, QoS = 0, retain = 0
m:publish("/topic","hello",0,0, function(conn) print("sent") end)

m:close();  -- if auto-reconnect == 1, will disable auto-reconnect and then disconnect from host.
-- you can call m:connect again

UDP client and server

-- a udp server
s=net.createServer(net.UDP)
s:on("receive",function(s,c) print(c) end)
s:listen(5683)

-- a udp client
cu=net.createConnection(net.UDP)
cu:on("receive",function(cu,c) print(c) end)
cu:connect(5683,"192.168.18.101")
cu:send("hello")

Do something shiny with an RGB LED

  function led(r,g,b)
    pwm.setduty(1,r)
    pwm.setduty(2,g)
    pwm.setduty(3,b)
  end
  pwm.setup(1,500,512)
  pwm.setup(2,500,512)
  pwm.setup(3,500,512)
  pwm.start(1)
  pwm.start(2)
  pwm.start(3)
  led(512,0,0) -- red
  led(0,0,512) -- blue
  lighton=0
  tmr.alarm(1,1000,1,function()
    if lighton==0 then
      lighton=1
      led(512,512,512)
    else
      lighton=0
      led(0,0,0)
    end
  end)

If you want to run something when the system boots

  --init.lua will be excuted
  file.open("init.lua","w")
  file.writeline([[print("Hello, do this at the beginning.")]])
  file.close()
  node.restart()  -- this will restart the module.

Add a simple telnet server to the Lua interpreter

    -- a simple telnet server
    s=net.createServer(net.TCP,180)
    s:listen(2323,function(c)
       function s_output(str)
          if(c~=nil)
             then c:send(str)
          end
       end
       node.output(s_output, 0)   -- re-direct output to function s_ouput.
       c:on("receive",function(c,l)
          node.input(l)           -- works like pcall(loadstring(l)) but support multiple separate line
       end)
       c:on("disconnection",function(c)
          node.output(nil)        -- un-regist the redirect output function, output goes to serial
       end)
       print("Welcome to NodeMcu world.")
    end)

Building the firmware

There are several options for building the NodeMCU firmware.

Online firmware custom build

Please try Marcel's NodeMCU custom builds cloud service and you can choose only the modules you need, and download the firmware once built.

NodeMCU custom builds can build from the master branch (0.9.6; deprecated) and dev branch (1.4.0).

Docker containerised build

See https://hub.docker.com/r/asmaps/nodemcu-builder/

This docker image includes the build toolchain and SDK. You just run the docker image with your checked-out NodeMCU firmware repository (this one). The docker image can also flash the firmware to your device.

You will need to see BUILD OPTIONS below, to configure the firmware before building.

Build it yourself

See BUILD OPTIONS below, to configure the firmware before building.

Minimum requirements:

Build instructions:

Assuming NodeMCU firmware is checked-out to /opt/nodemcu-firmware:

git clone --recursive https://github.com/pfalcon/esp-open-sdk.git /opt/esp-open-sdk
cd /opt/esp-open-sdk
make STANDALONE=y
PATH=/opt/esp-open-sdk/xtensa-lx106-elf/bin:$PATH
cd /opt/nodemcu-firmware
make

BUILD OPTIONS

Disable modules you won't be using, to reduce firmware size on flash and free more RAM. The ESP8266 is quite limited in available RAM, and running out can cause a system panic.

Edit app/include/user_modules.h

Comment-out the #define statement for unused modules. Example:

#ifdef LUA_USE_MODULES
#define LUA_USE_MODULES_NODE
#define LUA_USE_MODULES_FILE
#define LUA_USE_MODULES_GPIO
#define LUA_USE_MODULES_WIFI
#define LUA_USE_MODULES_NET
#define LUA_USE_MODULES_PWM
#define LUA_USE_MODULES_I2C
#define LUA_USE_MODULES_SPI
#define LUA_USE_MODULES_TMR
#define LUA_USE_MODULES_ADC
#define LUA_USE_MODULES_UART
#define LUA_USE_MODULES_OW
#define LUA_USE_MODULES_BIT
#define LUA_USE_MODULES_MQTT
// #define LUA_USE_MODULES_COAP
// #define LUA_USE_MODULES_U8G
// #define LUA_USE_MODULES_WS2801
// #define LUA_USE_MODULES_WS2812
// #define LUA_USE_MODULES_CJSON
#define LUA_USE_MODULES_CRYPTO
#define LUA_USE_MODULES_RC
#define LUA_USE_MODULES_DHT
#define LUA_USE_MODULES_RTCMEM
#define LUA_USE_MODULES_RTCTIME
#define LUA_USE_MODULES_RTCFIFO
#define LUA_USE_MODULES_SNTP
// #define LUA_USE_MODULES_BMP085
#define LUA_USE_MODULES_TSL2561
// #define LUA_USE_MODULES_HX711

#endif /* LUA_USE_MODULES */

Tagging your build

Identify your firmware builds by editing app/include/user_version.h

#define NODE_VERSION    "NodeMCU 1.4.0+myname"
#ifndef BUILD_DATE
#define BUILD_DATE        "YYYYMMDD"
#endif

GPIO NEW TABLE (Build 20141219 and later)

IO indexESP8266 pinIO indexESP8266 pin
0 [*]GPIO168GPIO15 (SPI CS)
1GPIO59GPIO3 (UART RX)
2GPIO410GPIO1 (UART TX)
3GPIO011GPIO9
4GPIO212GPIO10
5GPIO14 (SPI CLK)
6GPIO12 (SPI MISO)
7GPIO13 (SPI MOSI)
#### [*] D0(GPIO16) can only be used as gpio read/write. no interrupt supported. no pwm/i2c/ow supported.

#Flash the firmware nodemcu_latest.bin: 0x00000
for most esp8266 modules, just pull GPIO0 down and restart.
You can use the nodemcu-flasher to burn the firmware.

Or, if you build your own bin from source code.
0x00000.bin: 0x00000
0x10000.bin: 0x10000

Better run file.format() after flash

#Connect the hardware in serial baudrate:9600

#Write Lua script to filesystem ####Esplorer Victor Brutskiy's Esplorer support most platforms such as Linux, Windows, Mac OS, etc. This software is opensource and can write lua/lc files to filesystem.

####NodeMCU Studio NodeMCU Studio is written in C# and support Windows. This software is opensource and can write lua files to filesystem.

OPTIONAL MODULES

####Use DS18B20 module extends your esp8266

    -- read temperature with DS18B20
    node.compile("ds18b20.lua")   --  run this only once to compile and save to "ds18b20.lc"
    t=require("ds18b20")
    t.setup(9)
    addrs=t.addrs()
    -- Total DS18B20 numbers, assume it is 2
    print(table.getn(addrs))
    -- The first DS18B20
    print(t.read(addrs[1],t.C))
    print(t.read(addrs[1],t.F))
    print(t.read(addrs[1],t.K))
    -- The second DS18B20
    print(t.read(addrs[2],t.C))
    print(t.read(addrs[2],t.F))
    print(t.read(addrs[2],t.K))
    -- Just read
    print(t.read())
    -- Just read as centigrade
    print(t.read(nil,t.C))
    -- Don't forget to release it after use
    t = nil
	ds18b20 = nil
    package.loaded["ds18b20"]=nil

####Operate a display with u8glib u8glib is a graphics library with support for many different displays. The nodemcu firmware supports a subset of these. Both I2C and SPI:

  • sh1106_128x64
  • ssd1306 - 128x64 and 64x48 variants
  • ssd1309_128x64
  • ssd1327_96x96_gr
  • uc1611 - dogm240 and dogxl240 variants

SPI only:

  • ld7032_60x32
  • pcd8544_84x48
  • pcf8812_96x65
  • ssd1322_nhd31oled - bw and gr variants
  • ssd1325_nhd27oled - bw and gr variants
  • ssd1351_128x128 - gh and hicolor variants
  • st7565_64128n - variants 64128n, dogm128/132, lm6059/lm6063, c12832/c12864
  • uc1601_c128032
  • uc1608 - 240x128 and 240x64 variants
  • uc1610_dogxl160 - bw and gr variants
  • uc1611 - dogm240 and dogxl240 variants
  • uc1701 - dogs102 and mini12864 variants

U8glib v1.18.1

#####I2C connection Hook up SDA and SCL to any free GPIOs. Eg. u8g_graphics_test.lua expects SDA=5 (GPIO14) and SCL=6 (GPIO12). They are used to set up nodemcu's I2C driver before accessing the display:

sda = 5
scl = 6
i2c.setup(0, sda, scl, i2c.SLOW)

#####SPI connection The HSPI module is used, so certain pins are fixed:

  • HSPI CLK = GPIO14
  • HSPI MOSI = GPIO13
  • HSPI MISO = GPIO12 (not used)

All other pins can be assigned to any available GPIO:

  • CS
  • D/C
  • RES (optional for some displays)

Also refer to the initialization sequence eg in u8g_graphics_test.lua:

spi.setup(1, spi.MASTER, spi.CPOL_LOW, spi.CPHA_LOW, 8, 8)

#####Library usage The Lua bindings for this library closely follow u8glib's object oriented C++ API. Based on the u8g class, you create an object for your display type.

SSD1306 via I2C:

sla = 0x3c
disp = u8g.ssd1306_128x64_i2c(sla)

SSD1306 via SPI:

cs  = 8 -- GPIO15, pull-down 10k to GND
dc  = 4 -- GPIO2
res = 0 -- GPIO16, RES is optional YMMV
disp = u8g.ssd1306_128x64_hw_spi(cs, dc, res)

This object provides all of u8glib's methods to control the display. Again, refer to u8g_graphics_test.lua to get an impression how this is achieved with Lua code. Visit the u8glib homepage for technical details.

#####Displays I2C and HW SPI based displays with support in u8glib can be enabled. To get access to the respective constructors, add the desired entries to the I2C or SPI display tables in app/include/u8g_config.h:

#define U8G_DISPLAY_TABLE_I2C                   \
    U8G_DISPLAY_TABLE_ENTRY(ssd1306_128x64_i2c) \

#define U8G_DISPLAY_TABLE_SPI                      \
    U8G_DISPLAY_TABLE_ENTRY(ssd1306_128x64_hw_spi) \
    U8G_DISPLAY_TABLE_ENTRY(pcd8544_84x48_hw_spi)  \
    U8G_DISPLAY_TABLE_ENTRY(pcf8812_96x65_hw_spi)  \

An exhaustive list of available displays can be found in the u8g module wiki entry.

#####Fonts u8glib comes with a wide range of fonts for small displays. Since they need to be compiled into the firmware image, you'd need to include them in app/include/u8g_config.h and recompile. Simply add the desired fonts to the font table:

#define U8G_FONT_TABLE \
    U8G_FONT_TABLE_ENTRY(font_6x10)  \
    U8G_FONT_TABLE_ENTRY(font_chikita)

They'll be available as u8g.<font_name> in Lua.

#####Bitmaps Bitmaps and XBMs are supplied as strings to drawBitmap() and drawXBM(). This off-loads all data handling from the u8g module to generic methods for binary files. See u8g_bitmaps.lua. In contrast to the source code based inclusion of XBMs into u8glib, it's required to provide precompiled binary files. This can be performed online with Online-Utility's Image Converter: Convert from XBM to MONO format and upload the binary result with nodemcu-uploader.py.

#####Unimplemented functions

  • Cursor handling
    • disableCursor()
    • enableCursor()
    • setCursorColor()
    • setCursorFont()
    • setCursorPos()
    • setCursorStyle()
  • General functions
    • setContrast()
    • setPrintPos()
    • setHardwareBackup()
    • setRGB()
    • setDefaultMidColor()

####Operate a display with ucglib Ucglib is a graphics library with support for color TFT displays.

Ucglib v1.3.3

#####SPI connection The HSPI module is used, so certain pins are fixed:

  • HSPI CLK = GPIO14
  • HSPI MOSI = GPIO13
  • HSPI MISO = GPIO12 (not used)

All other pins can be assigned to any available GPIO:

  • CS
  • D/C
  • RES (optional for some displays)

Also refer to the initialization sequence eg in GraphicsTest.lua:

spi.setup(1, spi.MASTER, spi.CPOL_LOW, spi.CPHA_LOW, 8, 8)

#####Library usage The Lua bindings for this library closely follow ucglib's object oriented C++ API. Based on the ucg class, you create an object for your display type.

ILI9341 via SPI:

cs  = 8 -- GPIO15, pull-down 10k to GND
dc  = 4 -- GPIO2
res = 0 -- GPIO16, RES is optional YMMV
disp = ucg.ili9341_18x240x320_hw_spi(cs, dc, res)

This object provides all of ucglib's methods to control the display. Again, refer to GraphicsTest.lua to get an impression how this is achieved with Lua code. Visit the ucglib homepage for technical details.

#####Displays To get access to the display constructors, add the desired entries to the display table in app/include/ucg_config.h:

#define UCG_DISPLAY_TABLE                          \
    UCG_DISPLAY_TABLE_ENTRY(ili9341_18x240x320_hw_spi, ucg_dev_ili9341_18x240x320, ucg_ext_ili9341_18) \
    UCG_DISPLAY_TABLE_ENTRY(st7735_18x128x160_hw_spi, ucg_dev_st7735_18x128x160, ucg_ext_st7735_18) \

#####Fonts ucglib comes with a wide range of fonts for small displays. Since they need to be compiled into the firmware image, you'd need to include them in app/include/ucg_config.h and recompile. Simply add the desired fonts to the font table:

#define UCG_FONT_TABLE                              \
    UCG_FONT_TABLE_ENTRY(font_7x13B_tr)             \
    UCG_FONT_TABLE_ENTRY(font_helvB12_hr)           \
    UCG_FONT_TABLE_ENTRY(font_helvB18_hr)           \
    UCG_FONT_TABLE_ENTRY(font_ncenR12_tr)           \
    UCG_FONT_TABLE_ENTRY(font_ncenR14_hr)

They'll be available as ucg.<font_name> in Lua.

####Control a WS2812 based light strip

	-- set the color of one LED on GPIO2 to red
	ws2812.writergb(4, string.char(255, 0, 0))
	-- set the color of 10 LEDs on GPIO0 to blue
	ws2812.writergb(3, string.char(0, 0, 255):rep(10))
	-- first LED green, second LED white
	ws2812.writergb(4, string.char(0, 255, 0, 255, 255, 255))

####coap client and server

-- use copper addon for firefox
cs=coap.Server()
cs:listen(5683)

myvar=1
cs:var("myvar") -- get coap://192.168.18.103:5683/v1/v/myvar will return the value of myvar: 1

-- function should tack one string, return one string.
function myfun(payload)
  print("myfun called")
  respond = "hello"
  return respond
end
cs:func("myfun") -- post coap://192.168.18.103:5683/v1/f/myfun will call myfun

cc = coap.Client()
cc:get(coap.CON, "coap://192.168.18.100:5683/.well-known/core")
cc:post(coap.NON, "coap://192.168.18.100:5683/", "Hello")

####cjson

-- Note that when cjson deal with large content, it may fails a memory allocation, and leaks a bit of memory.
-- so it's better to detect that and schedule a restart. 
--
-- Translate Lua value to/from JSON
-- text = cjson.encode(value)
-- value = cjson.decode(text)
json_text = '[ true, { "foo": "bar" } ]'
value = cjson.decode(json_text)
-- Returns: { true, { foo = "bar" } }
value = { true, { foo = "bar" } }
json_text = cjson.encode(value)
-- Returns: '[true,{"foo":"bar"}]'

####Read an HX711 load cell ADC. Note: currently only chanel A with gain 128 is supported. The HX711 is an inexpensive 24bit ADC with programmable 128x, 64x, and 32x gain.

	-- Initialize the hx711 with clk on pin 5 and data on pin 6
	hx711.init(5,6)
	-- Read ch A with 128 gain.
	raw_data = hx711.read(0)