Me pareció muy interesante el ejemplo anterior y empecé a estudiar un poco el funcionamiento.
El firmware que le flasheamos es un intérprete de lua y microphyton. En este ejemplo se ve el poder de phyton para manejar cadenas. Veamos que hace cada línea. He modificado un poco el código para poder capturar y mostrar las transferencias http que se suceden:
wifi.setmode(wifi.STATION)
wifi.sta.config("elgarbe","1234567890123")
wifi.sta.setip({ip="192.168.1.5",netmask="255.255.255.0",gateway="192.168.1.1"}) --configura IP fija
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)
print("Request: " .. request)
local buf = "";
local a, b, method, path, vars = string.find(request, "([A-Z]+) (.+)?(.+) HTTP");
if (a ~= nil)then
print("Start: " .. a)
end
if (b ~= nil)then
print("End: " .. b)
end
if (method ~= nil)then
print("Method: " .. method)
end
if (path ~= nil)then
print("Path: " .. path)
end
if (vars ~= nil)then
print("Vars: " .. vars)
end
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)
Las primeras líneas son típicas, configurar el nodo como estacion y lo conectan al router que elijamos, finalmente nos damos una ip fija:
wifi.setmode(wifi.STATION)
wifi.sta.config("elgarbe","1234567890123")
wifi.sta.setip({ip="192.168.1.5",netmask="255.255.255.0",gateway="192.168.1.1"}) --configura IP fija
Luego viene la inicializacion del hardware:
led1 = 3
led2 = 4
gpio.mode(led1, gpio.OUTPUT)
gpio.mode(led2, gpio.OUTPUT)
porque el gpio0 es igual a 3 y el gpio2 es igual a 4 es algo que estoy averiguando.
Luego viene la creacion del webserver escuchando en el puerto 80 y la funcion a llamar cuando se recive el evento on receive
srv=net.createServer(net.TCP)
srv:listen(80,function(conn)
conn:on("receive", function(client,request)
dentro de "request" tenemos la informacion que envía el navegador web que quiere conectarse
Si ejecutáramos el código hasta ahí tendríamos lo siguiente:
como se ve, la primer línea del reques es: GET / HTTP/1.1
cuando en el navegador pasamos algún argumento en la direccion, como por ejemplo
http://192.168.1.5/?pin=OFF2 esa cadena adicion aparecerá en esa línea.
Agreguemos más codigo:
conn:on("receive", function(client,request)
print("Request: " .. request)
local buf = "";
local a, b, method, path, vars = string.find(request, "([A-Z]+) (.+)?(.+) HTTP");
if (a ~= nil)then
print("Start: " .. a)
end
if (b ~= nil)then
print("End: " .. b)
end
if (method ~= nil)then
print("Method: " .. method)
end
if (path ~= nil)then
print("Path: " .. path)
end
if (vars ~= nil)then
print("Vars: " .. vars)
end
end)
Aquí aparece el phyton, que debería haver estudiado antes!!!!.
Cada instruccion (string.find por ejemplo) la podemos encontrar en el manual que puso groundman al principio.
En este caso la instruccion local a, b, method, path, vars = string.find(request, "([A-Z]+) (.+)?(.+) HTTP");
declara 5 variables locales. a y b almacenan el comienzo y el final del string buscado ("([A-Z]+) (.+)?(.+) HTTP") en la cadena request.
Luego method, path y vars almacenan el texto encontrado según el pattern ("([A-Z]+) (.+)?(.+) HTTP"). Cada variable almacena lo que está en paréntesis.
Entonces method almacenará la cadena que concuerde con el pattern [A-Z]+ esto es, tantos caracteres como haya mientras que estén dentro del entorno A-Z
Luego se buscará un espacio en blanco
luego se buscará un caracter cualquiera (.) y tantos como haya (+) y se almacenará en path. Aquí estimo que la cantidad de caracteres se corta al hayar el próximo del pattern general, en este caso el ?
Luego el signo de pregunta
Luego se busca cualquier caracter y tantos como haya hasta encotrar el resto del pttern " HTTP" y se almacena en vars.
Etonces el código anterior con la siguiente direccion del navegador:
http://192.168.1.5/?pin=OFF2 devuelve:
como vemos el resutado es:
> Request: GET /?pin=OFF2 HTTP/1.1
Host: 192.168.1.5
User-Agent: Mozilla/5.0 (Windows NT 6.1; rv:43.0) Gecko/20100101 Firefox/43.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: es-AR,es;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Connection: keep-alive
Start: 1
End: 19
Method: GET
Path: /
Vars: pin=OFF2
Como ven se almacena en cada variable la parte del GET que nos interesa. Lo importante acá es vars que nos da el comando a ejecutar.
Luego, como start y end (a y b) no nos interesa lo podemos reemplazar por "_":
wifi.setmode(wifi.STATION)
wifi.sta.config("elgarbe","1234567890123")
wifi.sta.setip({ip="192.168.1.5",netmask="255.255.255.0",gateway="192.168.1.1"}) --configura IP fija
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)
print("Request: " .. request)
local buf = "";
local _, _, method, path, vars = string.find(request, "([A-Z]+) (.+)?(.+) HTTP");
if (method ~= nil)then
print("Method: " .. method)
end
if (path ~= nil)then
print("Path: " .. path)
end
if (vars ~= nil)then
print("Vars: " .. vars)
end
end)
end)
Hasta ahora en el explorador no aparece nada al escrivir la direccion. Agreguemos ahora código para la interfaz:
wifi.setmode(wifi.STATION)
wifi.sta.config("elgarbe","1234567890123")
wifi.sta.setip({ip="192.168.1.5",netmask="255.255.255.0",gateway="192.168.1.1"}) --configura IP fija
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)
print("Request: " .. request)
local buf = "";
local a, b, method, path, vars = string.find(request, "([A-Z]+) (.+)?(.+) HTTP");
if (a ~= nil)then
print("Start: " .. a)
end
if (b ~= nil)then
print("End: " .. b)
end
if (method ~= nil)then
print("Method: " .. method)
end
if (path ~= nil)then
print("Path: " .. path)
end
if (vars ~= nil)then
print("Vars: " .. vars)
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>";
client:send(buf);
client:close();
collectgarbage();
end)
end)
Con ese código ya tenemos la página web que nos permitirá enviar los comandos con 4 botones de comando.
Ahora veamos el código que determina el comando (ON OFF) y el pin (1 o 2).
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
print("k: " .. k .. "\nv: " .. v)
end
end
En estas líneas no entiendo bien la funcion del primer if.
Luego si vars no es nulo (o sea, si hemos agregado algun GET en la direccion del explorador) hacemos un for buscando en vars el pattern que esta entre paréntesis. vars contiene, por ejemplo pin=ON2. El patern está dividido por el signo "=" y lo que se busca de un lado y del otro es %w (todos los caracteres alfanuméricos) y el + es tantos como haya. Entonces al ejecutar el código con ese agregado obtenemos al precionar ON del LED 2:
Request: GET /?pin=ON2 HTTP/1.1
Host: 192.168.1.5
User-Agent: Mozilla/5.0 (Windows NT 6.1; rv:43.0) Gecko/20100101 Firefox/43.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: es-AR,es;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Referer: http://192.168.1.5/
Connection: keep-alive
Method: GET
Path: /
Vars: pin=ON2
k: pin
v: ON2
Entonces se ha separado pin de comando. La variable _GET es tipo array y la instruccion _GET[k] = v hace que GET[pin] tome el valor de v (ON2)
Finalmente, el código que toma el array GET y actua sobre los led:
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
aquí no se bien para que sirve local _on,_off = "",""
Bueno, hemos podido explicar el primer ejemplo, el cual puede ser base de cualquier otro proyecto que espere comndos para actuar en cuestion.
Saludos!