I bought a
NodeMcu Lua CH340G ESP8266 Wireless WIFI Internet Development Board Module TE437. First impression was bad, because it comes with no manual and the examples from
http://www.nodemcu.com didn't work. Fortunately I found
this page, which explains how to start working with it. I'll post the relevant information from it for my module, and at the end some advanced stuff for rapid development, where you can edit a Lua script on PC, and load it to the module over wifi with just pressing the reset button on it.
I tested the board in Linux. lsusb shows this information:
Bus 001 Device 012: ID 1a86:7523 QinHeng Electronics HL-340 USB-Serial adapter
The board is a 0.9 hardware version according to the CNXSoft blog, with some disadvantages compared to the latest 1.0 version (wrong pin distance for a breadboard, fewer GPIOs). I can connect to the board with minicom (note: you have to disable hardware flow control, if enabled. On Windows you can use putty or any other terminal program that supports COM ports) :
minicom --device /dev/ttyUSB0 --baudrate 115200
After pressing the reset button (it resets the ESP8266 module only, not the USB virtual COM port chip) it shows this information:
Ai-Thinker Technology Co. Ltd.
ready
I guess this is an old version or the AT command version, but no AT commands work. Ok, so I installed the latest pre-compiled firmware:
wget https://github.com/nodemcu/nodemcu-firmware/releases/download/0.9.6-dev_20150704/nodemcu_float_0.9.6-dev_20150704.bin
git clone https://github.com/themadinventor/esptool.git
cd esptool
sudo python2 ./esptool.py --port /dev/ttyUSB0 write_flash 0x00000 ../nodemcu_float_0.9.6-dev_20150704.bin
(if there is an error "ImportError: No module named serial", then do a "sudo python2 -m pip install pyserial". If you have only Python 2.x installed, you can use "python" instead of "python2", this is just my system, where I have Python 3.x installed, too).
Then I can start minicom again. With 115200 baud it shows some garbage text and "MEM CHECK FAIL!!!" after reset. Looks like like there is still some problem, but it works. Later it switches to 9600 baud. When using 9600 baud, I can read this:
NodeMCU 0.9.6 build 20150704 powered by Lua 5.1.4
lua: cannot open init.lua
>
Now I can interactively enter
print("Hello Lua")
and it executes the command, and the examples from
http://www.nodemcu.com work, too. That's a good start! Maybe the eBay seller just didn't care to flash the right firmware version.
Now let's implement a webserver, which toggles the LED and another GPIO pin. Save this as init.lua (slightly modified script from the CNXSoft blog) :
wifi.setmode(wifi.STATION)
wifi.sta.config("ROUTER_ESSID","WIFI_PASSWORD")
print(wifi.sta.getip())
gpio.mode(0, gpio.OUTPUT)
gpio.mode(4, gpio.OUTPUT)
srv=net.createServer(net.TCP)
srv:listen(80,function(conn)
conn:on("receive", function(client,request)
local buf = "";
local _, _, method, path, vars = string.find(request, "([A-Z]+) (.+)?(.+) HTTP");
if(method == nil)then
_, _, method, path = string.find(request, "([A-Z]+) (.+) HTTP");
end
local _GET = {}
if (vars ~= nil)then
for k, v in string.gmatch(vars, "(%w+)=(%w+)&*") do
_GET[k] = v
end
end
buf = buf.."<h1> ESP8266 Web Server</h1>";
buf = buf.."<p>GPIO0 <a href=\"?pin=ON1\"><button>ON</button></a> <a href=\"?pin=OFF1\"><button>OFF</button></a></p>";
buf = buf.."<p>GPIO4 / LED <a href=\"?pin=ON2\"><button>ON</button></a> <a href=\"?pin=OFF2\"><button>OFF</button></a></p>";
local _on,_off = "",""
if(_GET.pin == "ON1")then
gpio.write(0, gpio.HIGH);
elseif(_GET.pin == "OFF1")then
gpio.write(0, gpio.LOW);
elseif(_GET.pin == "ON2")then
gpio.write(4, gpio.HIGH);
elseif(_GET.pin == "OFF2")then
gpio.write(4, gpio.LOW);
end
client:send(buf);
client:close();
collectgarbage();
end)
end)
Replace ROUTER_ESSID and WIFI_PASSWORD with your router information. You can upload it to the module like this:
git clone https://github.com/4refr0nt/luatool.git
python luatool/luatool/luatool.py --port /dev/ttyUSB0 --src init.lua --dest init.lua --restart
After flashing, it restarts the module. With minicom you can get the IP address:
= wifi.sta.getip()
("=" is a shortcut for "print" in the Lua shell)
GPIO0 is labeled D0 on the board and GPIO4 is D4, and the blue LED on the board. That's one direction of an "internet of things" thing, now the other direction, the thing calling the internet.
What I really like about Lua is the interactive shell in minicom, you can try anything you want without the usual compile/upload/run cycle. For a full API documentation take a look at
http://nodemcu.readthedocs.io/en/master/ I have a local Apache server installed on my PC. To get a page from it, I can enter this in minicom (one line at a time, looks like it has some problems when you paste lots of data) :
conn = net.createConnection(net.TCP, false)
conn:on("receive", function(conn, pl) print(pl) end)
conn:connect(80, "192.168.11.27")
conn:send("GET /init2.lua HTTP/1.1\r\nHost: localhost\r\n\r\n")
Another nice feature of Lua is that you can execute source code from within Lua:
> test1='print("test")'
> test2=loadstring(test1)
> test2()
test
Putting it all together and for faster development, this init.lua script loads the file init2.lua from a server and executes it:
wifi.setmode(wifi.STATION)
wifi.sta.config("ROUTER_ESSID","WIFI_PASSWORD")
function executeString(s)
local fun = loadstring(s)
fun()
end
function stripHeader(s)
local pos = string.find(s, "\r\n\r\n")
return s:sub(pos + 4)
end
function runScript(host, url)
receivedPage = ""
conn = net.createConnection(net.TCP, false)
conn:on("receive", function(conn, data) receivedPage = receivedPage .. data end)
conn:on("disconnection", function(conn, data) executeString(stripHeader(receivedPage)) end)
conn:connect(80, host)
conn:send("GET /" .. url .. " HTTP/1.1\r\nHost: " .. host .. "\r\nConnection: close\r\n\r\n")
end
tmr.alarm(0, 3000, 1, function() tmr.stop(0) runScript("192.168.11.27","init2.lua") end)
The 3 second delay before starting is necessary, because it needs some time after reset to establish the wifi connection. In later releases of the firmware you can use wifi.sta.eventMonReg, but for this you have to build your own version of the firmware, or use the firmware build service here:
https://nodemcu-build.com For the the later releases they don't provide a default firmware anymore, because they say there are too many modules which the user can select. Yeah, good idea for beginners
With this setup, I can just change init2.lua on my PC, then hit the reset button on the module and the new code gets loaded. Once I'm done with developing, I can upload init2.lua to the platform, so that I don't need a local webserver anymore.
An interesting application is to get data from the web and display it with some device, for example a clock. There is no internal clock in the firmware, but there is the rtctime module in later releases, which in combination with sntp.sync could be used to load the time from a NTP time server for initialization and then display it. Unfortunately none of these modules are in the old pre-compiled firmware archive.
A simple solution for the old firmware is to create a PHP page on your server which returns the time. The server can be synchronized with ntpd to a NTP time server. For example save this as time.php on your webserver:
<?php
date_default_timezone_set("Europe/Berlin");
echo date('H:i:s', time());
?>
Then save this code for init2.lua:
function showTime(s)
print(s)
end
function trim(s)
return s:match "^%s*(.-)%s*$"
end
function stripHeader(s)
local pos = string.find(s, "\r\n\r\n")
return s:sub(pos + 4)
end
function getTime(host)
receivedPage = ""
conn = net.createConnection(net.TCP, false)
conn:on("receive", function(conn, data) receivedPage = receivedPage .. data end)
conn:on("disconnection", function(conn, data) showTime(trim(stripHeader(receivedPage))) end)
conn:connect(80, host)
conn:send("GET /time.php HTTP/1.1\r\nHost: " .. host .. "\r\nConnection: close\r\n\r\n")
end
tmr.alarm(0, 1000, 1, function() getTime("192.168.11.27") end)
and in minicom you can see the time ticking after a reset:
NodeMCU 0.9.6 build 20150704 powered by Lua 5.1.4
> 14:25:48
14:25:49
14:25:50
14:25:51
14:25:52
14:25:53
14:25:54
14:25:55
Of course, instead of the time, the PHP script can return any other information you want to display. Controlling the GPIO pins to show the info with a Nixie tube or any other display in the showTime function is trivial and left as an excercise for the reader.
Conclusion: the firmware looks a bit rough, I wouldn't create mission critical projects with it, and if you bought a module with the wrong firmware, it is not easy for beginners to flash a new firmware and to get started, but once this is done and with my network load script, it is a nice platform for fast prototyping and hobby projects.