Mise en place d’un server web sur ESP8266 avec NodeMCU
J’en ai souvent parlé sur ce blog, et je pense que je n’ai pas fini de faire l’éloge du ESP8266. Ce petit module Wifi programmable est simplement génial. Nous allons voir dans cet article comment débuter avec un Module NodeMCU que vous pouvez trouver sur amazon pour largement moins de 10€. Attention, utiliser nodeMCU signifie programmer en Lua. Ca va changer un peu nos habitudes du C avec Arduino.
Installer le firmware NodeMCU
La première étape consiste à flasher le module avec le firmware NodeMCU, ici j’ai choisi d’utiliser le firmware 0.9. Notez que pour cette opération je suis sous MacOS. Les manipulations sont les mêmes sous Windows, mais l’environnement est à mon avais moins adapté au développement.
Télécharger le firmware ModeMCU
wget https://github.com/nodemcu/nodemcu-firmware/releases/download/0.9.6-dev_20150704/nodemcu_integer_0.9.6-dev_20150704.bin
Cloner le repository esptool qui est un programme python permettant de flasher le firmware téléchargé sur la carte.
git clone https://github.com/themadinventor/esptool.git
Avant de brancher le module lister les fichiers dans /dev/tty*, cela permettra de trouver le nouveau périphérique dans la liste
$>ls /dev/tty* /dev/tty /dev/ttyp6 /dev/ttypf /dev/ttyq8 /dev/ttyr1 /dev/ttyra /dev/ttys002 /dev/ttys011 /dev/ttys4 /dev/ttysd /dev/ttyt6 /dev/ttytf /dev/ttyu8 /dev/ttyv1 /dev/ttyva /dev/ttyw3 /dev/ttywc /dev/tty.Bluetooth-Incoming-Port /dev/ttyp7 /dev/ttyq0 /dev/ttyq9 /dev/ttyr2 /dev/ttyrb /dev/ttys003 /dev/ttys012 /dev/ttys5 /dev/ttyse /dev/ttyt7 /dev/ttyu0 /dev/ttyu9 /dev/ttyv2 /dev/ttyvb /dev/ttyw4 /dev/ttywd /dev/tty.iPhone-WirelessiAP /dev/ttyp8 /dev/ttyq1 /dev/ttyqa /dev/ttyr3 /dev/ttyrc /dev/ttys004 /dev/ttys013 /dev/ttys6 /dev/ttysf /dev/ttyt8 /dev/ttyu1 /dev/ttyua /dev/ttyv3 /dev/ttyvc /dev/ttyw5 /dev/ttywe /dev/ttyp0 /dev/ttyp9 /dev/ttyq2 /dev/ttyqb /dev/ttyr4 /dev/ttyrd /dev/ttys005 /dev/ttys014 /dev/ttys7 /dev/ttyt0 /dev/ttyt9 /dev/ttyu2 /dev/ttyub /dev/ttyv4 /dev/ttyvd /dev/ttyw6 /dev/ttywf /dev/ttyp1 /dev/ttypa /dev/ttyq3 /dev/ttyqc /dev/ttyr5 /dev/ttyre /dev/ttys006 /dev/ttys015 /dev/ttys8 /dev/ttyt1 /dev/ttyta /dev/ttyu3 /dev/ttyuc /dev/ttyv5 /dev/ttyve /dev/ttyw7 /dev/ttyp2 /dev/ttypb /dev/ttyq4 /dev/ttyqd /dev/ttyr6 /dev/ttyrf /dev/ttys007 /dev/ttys017 /dev/ttys9 /dev/ttyt2 /dev/ttytb /dev/ttyu4 /dev/ttyud /dev/ttyv6 /dev/ttyvf /dev/ttyw8 /dev/ttyp3 /dev/ttypc /dev/ttyq5 /dev/ttyqe /dev/ttyr7 /dev/ttys0 /dev/ttys008 /dev/ttys1 /dev/ttysa /dev/ttyt3 /dev/ttytc /dev/ttyu5 /dev/ttyue /dev/ttyv7 /dev/ttyw0 /dev/ttyw9 /dev/ttyp4 /dev/ttypd /dev/ttyq6 /dev/ttyqf /dev/ttyr8 /dev/ttys000 /dev/ttys009 /dev/ttys2 /dev/ttysb /dev/ttyt4 /dev/ttytd /dev/ttyu6 /dev/ttyuf /dev/ttyv8 /dev/ttyw1 /dev/ttywa /dev/ttyp5 /dev/ttype /dev/ttyq7 /dev/ttyr0 /dev/ttyr9 /dev/ttys001 /dev/ttys010 /dev/ttys3 /dev/ttysc /dev/ttyt5 /dev/ttyte /dev/ttyu7 /dev/ttyv0 /dev/ttyv9 /dev/ttyw2 /dev/ttywb
Repérer le nouveau périphérique USB. Pour moi c’est /dev/tty.wchusbserial1420.
NB: Si le périphérique n’est pas reconnu par votre système, suivez ce tutorial pour installer les driver sous MacOS: http://www.homautomation.org/2015/02/05/how-to-use-arduinos-with-ch340g-ch341g-serialusb-ftdi-chip/
$>ls /dev/tty* /dev/tty /dev/ttyp5 /dev/ttype /dev/ttyq7 /dev/ttyr0 /dev/ttyr9 /dev/ttys001 /dev/ttys010 /dev/ttys3 /dev/ttysc /dev/ttyt5 /dev/ttyte /dev/ttyu7 /dev/ttyv0 /dev/ttyv9 /dev/ttyw2 /dev/ttywb /dev/tty.Bluetooth-Incoming-Port /dev/ttyp6 /dev/ttypf /dev/ttyq8 /dev/ttyr1 /dev/ttyra /dev/ttys002 /dev/ttys011 /dev/ttys4 /dev/ttysd /dev/ttyt6 /dev/ttytf /dev/ttyu8 /dev/ttyv1 /dev/ttyva /dev/ttyw3 /dev/ttywc /dev/tty.iPhone-WirelessiAP /dev/ttyp7 /dev/ttyq0 /dev/ttyq9 /dev/ttyr2 /dev/ttyrb /dev/ttys003 /dev/ttys012 /dev/ttys5 /dev/ttyse /dev/ttyt7 /dev/ttyu0 /dev/ttyu9 /dev/ttyv2 /dev/ttyvb /dev/ttyw4 /dev/ttywd /dev/tty.wchusbserial1420 /dev/ttyp8 /dev/ttyq1 /dev/ttyqa /dev/ttyr3 /dev/ttyrc /dev/ttys004 /dev/ttys013 /dev/ttys6 /dev/ttysf /dev/ttyt8 /dev/ttyu1 /dev/ttyua /dev/ttyv3 /dev/ttyvc /dev/ttyw5 /dev/ttywe /dev/ttyp0 /dev/ttyp9 /dev/ttyq2 /dev/ttyqb /dev/ttyr4 /dev/ttyrd /dev/ttys005 /dev/ttys014 /dev/ttys7 /dev/ttyt0 /dev/ttyt9 /dev/ttyu2 /dev/ttyub /dev/ttyv4 /dev/ttyvd /dev/ttyw6 /dev/ttywf /dev/ttyp1 /dev/ttypa /dev/ttyq3 /dev/ttyqc /dev/ttyr5 /dev/ttyre /dev/ttys006 /dev/ttys015 /dev/ttys8 /dev/ttyt1 /dev/ttyta /dev/ttyu3 /dev/ttyuc /dev/ttyv5 /dev/ttyve /dev/ttyw7 /dev/ttyp2 /dev/ttypb /dev/ttyq4 /dev/ttyqd /dev/ttyr6 /dev/ttyrf /dev/ttys007 /dev/ttys017 /dev/ttys9 /dev/ttyt2 /dev/ttytb /dev/ttyu4 /dev/ttyud /dev/ttyv6 /dev/ttyvf /dev/ttyw8 /dev/ttyp3 /dev/ttypc /dev/ttyq5 /dev/ttyqe /dev/ttyr7 /dev/ttys0 /dev/ttys008 /dev/ttys1 /dev/ttysa /dev/ttyt3 /dev/ttytc /dev/ttyu5 /dev/ttyue /dev/ttyv7 /dev/ttyw0 /dev/ttyw9 /dev/ttyp4 /dev/ttypd /dev/ttyq6 /dev/ttyqf /dev/ttyr8 /dev/ttys000 /dev/ttys009 /dev/ttys2 /dev/ttysb /dev/ttyt4 /dev/ttytd /dev/ttyu6 /dev/ttyuf /dev/ttyv8 /dev/ttyw1 /dev/ttywa
Flasher le firmware avec esptool:
$> cd esptool $> sudo python ./esptool.py --port /dev/tty.wchusbserial1420 write_flash 0x00000 ../nodemcu_integer_0.9.6-dev_20150704.bin esptool.py v1.2-dev Connecting... Auto-detected Flash size: 32m Running Cesanta flasher stub... Flash params set to 0x0040 Writing 450560 @ 0x0... 450560 (100 %) Wrote 450560 bytes at 0x0 in 39.1 seconds (92.2 kbit/s)... Leaving...
Nous y voilà le module est prêt.
Acceder au firmaware via la console.
Une fois le firmware bien installé, il s’agit de le tester, NodeMCU délivre un accès au système via le port Série USB. Il faut donc un terminal pour communiquer avec le module. De mon côté, j’utilise le terminal de l’environnement Arduino qui sera bien suffisant pour cette tâche. (NodeMCU communique à la vitesse de 9600 baud).
J’exécute donc le test le plus simple:
>print("Test")
A ce stade tout fonctionne parfaitement, il faut maintenant mettre en place du code:
Mise en place d’un serveur Http
Le langage utilisé pour programmer les NodeMCU est le Lua. Pour plus d’information sur le langage je vous propose ce PDF: Lua http://thomaslauer.com/download/luarefv51.pdf
Voici donc le code que je veux charger sur mon module.
NB: il faut penser à changer ROUTER_ESSID et WIFI_PASSWORD par vos identifiants wifi.
wifi.setmode(wifi.STATION) wifi.sta.config("ROUTER_ESSID","WIFI_PASSWORD") print(wifi.sta.getip()) led1 = 3 led2 = 4 gpio.mode(led1, gpio.OUTPUT) gpio.mode(led2, 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>GPIO2 <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(led1, gpio.HIGH); elseif(_GET.pin == "OFF1")then gpio.write(led1, gpio.LOW); elseif(_GET.pin == "ON2")then gpio.write(led2, gpio.HIGH); elseif(_GET.pin == "OFF2")then gpio.write(led2, gpio.LOW); end client:send(buf); client:close(); collectgarbage(); end) end)
Il est possible évidemment de copier ligne par ligne ce code dans la console pour le faire fonctionner mais ce n’est pas l’idéal. Il existe un autre utilitaire permettant de charger du code dans sur le ModeMCU:
$> git clone https://github.com/4refr0nt/luatool.git
J’ai pour ma part sauvegarder le code précédent dans le fichier suivant: ~/Dev/lua/simpleserver/init.lua
, je vais donc le télécharger sur le ModeMCU. Mais avant ça, je conseille de faire un reset du ModeMCU pour éviter tout problème de port déjà ouvert ou autre.
$> python luatool/luatool/luatool.py --port /dev/tty.wchusbserial1420 --src ~/Dev/lua/simpleserver/init.lua --dest init.lua --restart ->file.open("init.lua", "w") -> ok ->file.close() -> ok ->file.remove("init.lua") -> ok ->file.open("init.lua", "w+") -> ok ->file.writeline([==[wifi.setmode(wifi.STATION)]==]) -> ok ->file.writeline([==[wifi.sta.config("ROUTER_ESSID","WIFI_PASSWORD")]==]) -> ok ->file.writeline([==[print(wifi.sta.getip())]==]) -> ok ->file.writeline([==[led1 = 3]==]) -> ok ->file.writeline([==[led2 = 4]==]) -> ok ->file.writeline([==[gpio.mode(led1, gpio.OUTPUT)]==]) -> ok ->file.writeline([==[gpio.mode(led2, gpio.OUTPUT)]==]) -> ok ->file.writeline([==[srv=net.createServer(net.TCP)]==]) -> ok ->file.writeline([==[srv:listen(80,function(conn)]==]) -> ok ->file.writeline([==[conn:on("receive", function(client,request)]==]) -> ok ->file.writeline([==[local buf = "";]==]) -> ok ->file.writeline([==[local _, _, method, path, vars = string.find(request, "([A-Z]+) (.+)?(.+) HTTP");]==]) -> ok ->file.writeline([==[if(method == nil)then]==]) -> ok ->file.writeline([==[_, _, method, path = string.find(request, "([A-Z]+) (.+) HTTP");]==]) -> ok ->file.writeline([==[end]==]) -> ok ->file.writeline([==[local _GET = {}]==]) -> ok ->file.writeline([==[if (vars ~= nil)then]==]) -> ok ->file.writeline([==[for k, v in string.gmatch(vars, "(%w+)=(%w+)&*") do]==]) -> ok ->file.writeline([==[_GET[k] = v]==]) -> ok ->file.writeline([==[end]==]) -> ok ->file.writeline([==[end]==]) -> ok ->file.writeline([==[buf = buf.."<h1> ESP8266 Web Server</h1>";]==]) ->file.writeline([==[buf = buf.."<p>GPIO0 <a href=\"?pin=ON1\"><button>ON</button></a> <a href=\"?pin=OFF1\"><button>OFF</button></a></p>";]==]) ->file.writeline([==[buf = buf.."<p>GPIO2 <a href=\"?pin=ON2\"><button>ON</button></a> <a href=\"?pin=OFF2\"><button>OFF</button></a></p>";]==]) ->file.writeline([==[local _on,_off = "",""]==]) ->file.writeline([==[if(_GET.pin == "ON1")then]==]) -> ok ->file.writeline([==[gpio.write(led1, gpio.HIGH);]==]) -> ok ->file.writeline([==[elseif(_GET.pin == "OFF1")then]==]) -> ok ->file.writeline([==[gpio.write(led1, gpio.LOW);]==]) -> ok ->file.writeline([==[elseif(_GET.pin == "ON2")then]==]) -> ok ->file.writeline([==[gpio.write(led2, gpio.HIGH);]==]) -> ok ->file.writeline([==[elseif(_GET.pin == "OFF2")then]==]) -> ok ->file.writeline([==[gpio.write(led2, gpio.LOW);]==]) -> ok ->file.writeline([==[end]==]) -> ok ->file.writeline([==[client:send(buf);]==]) -> ok ->file.writeline([==[client:close();]==]) -> ok ->file.writeline([==[collectgarbage();]==]) -> ok ->file.writeline([==[end)]==]) -> ok ->file.writeline([==[end)]==]) -> ok ->file.flush() -> ok ->file.close() -> ok ->node.restart() -> ok --->>> All done <<<---
Test de l’application
Voilà tout est prêt. Pour tester cela il nous faut connaitre l’IP du NodeMCU. Pour cela se connecter à nouveau via le serial et taper:
> print(wifi.sta.getip()) 192.168.0.21 255.255.255.0 192.168.0.1
Il ne reste maintenant à se connecter sur cette ip pour tester.
Connecter une led sur le GPIO0
Pour finir de bien valider que tout fonctionne, on va ajouter une LED sur le GPIO0. Il nous faut pour cela le “pinout” de NodeMCU:
Nous pouvons donc utiliser le montage suivant:
NB: vous pouvez télécharger le composant NodeMCU pour Fritzing ici
Le résultat en image:
Acheter un ModeMCU:
Source: http://www.cnx-software.com/2015/10/29/getting-started-with-nodemcu-board-powered-by-esp8266-wisoc/
pour installer esptool:
sudo pip install esptool
c’est plus simple 😉
un soft très cool aussi comme terminal en solo: CoolTerm http://freeware.the-meiers.org/
Aussi, il y a une super interface pour les esp8266: http://esp8266.ru/esplorer/