-- Задаем режим работы esp8266, как wi-fi клиент
wifi.setmode(wifi.STATION)
-- Подключаемся к wi-fi сети ("Имясети","пароль")
wifi.sta.config("Homewifi","12345678")
-- Пишем в UART полученные настройки (IP, Mask, Gateway)
print(wifi.sta.getip())
-- Задаем переменную led1 = IO 3 = GPIO 15 (по таблице с API NodeMCU)
led1 = 3
-- Задаем переменную led1 = IO 4 = GPIO 3 (по таблице с API NodeMCU)
led2 = 4
-- переменные обычно "объявляются", а не задаются и далее им "присваивается значение"
-- во многих современных языках это делается сразу в 1 строку
-- причем еще и без явного указания типа (кому-то это по душе. а кто-то яро против, но вот так)
-- так что строка
led2 = 4
-- правильно читается как: объявляем переменную led2 (если это первый раз, где мы к ней обращаемся в коде)
-- и присваиваем ей значение 4 (целочисленного типа в данном случае)
-- Переключаем GPIO в режим выхода
gpio.mode(led1, gpio.OUTPUT)
-- Второй GPIO подключаем к ШИМ каналу указываем в скобках (номер GPIO, частота ШИМ, коэфициент заполнения ШИМ (обратная скважности) по умолчанию)
pwm.setup(led2, 10, 512)
-- Создаем TCP сервер (вызовом команды net.createServer)
-- Результат выполнения этой команды (ссылку на созданный сервер) помещаем в переменную srv
srv = net.createServer(net.TCP)
-- к слову сказать, если сейчас уже присутствует более новая версия функции net.createServer с бОльшим числом параметров,
-- то правильнее будет использовать ее, так как обратная совместимость может рано или поздно и перестать работать.
-- Другими словами, если вы используете более новую прошивку (версию функций и языка), то код нужно приводить в
-- соответствие с ними, если не хотите потом заново весь код обыскивать, когда что-то перестанет вдруг работать.
-- нужно понимать, что выполняются строки справа налево, а точнее, сначала выполняется то, что стоит справа от символа присвоения "="
-- и только потом результат этого выполнения присваивается тому, что записано слева от "="
-- соответственно и читать стоит сначала то, что справа, а потом то, что слева от "="
-- Говорим созданному ранее TCP серверу, который у нас в переменной srv, слушать порт 80
-- При подключении клиентов на этот порт этого сервера будет вызываться наша функция,
-- которая объявлена тут же inline так сказать, с единственным параметром-переменной.
-- В эту переменную будет передана ссылка на созданный для подключенного клиента socket
-- (попадет эта ссылка в переменную conn, назвать эту переменную мы могли и по-другому, при желании)
srv:listen(80, function(conn)
-- Когда клиент к нам подключится, мы тут же для соединения с ним объявим еще одну функцию
-- по событию receive (что-то получили от клиента). Будет вызвана наша inline функция,
-- в которую будет передано 2 параметра: client - думаю, ссылка на клиента, который послал нам запрос,
-- и request - думаю, что текст запроса в виде строки
conn:on("receive", function(client, request)
-- объявляем локальную переменную buf, помещаем в нее пустую строку
local buf = "";
-- объявляем 5 локальных переменных
-- _, _, method, path, vars
-- помещаем в эти 5 переменных результат вызова функции string.find
-- уверен, что это поиск подстроки "([A-Z]+) (.+)?(.+) HTTP" в строке request
-- в интернетах легко найти точное описание, набрав нечто вроде LUA string.find в любом поисковике
local _, _, method, path, vars = string.find(request, "([A-Z]+) (.+)?(.+) HTTP");
-- если method не nil (думаю, "не пусто", это значит, что мы нашли ту искому подстроку ранее)
if(method == nil) then
-- тогда снова ищем другую подстроку "([A-Z]+) (.+) HTTP" там же в request
_, _, method, path = string.find(request, "([A-Z]+) (.+) HTTP");
end
-- объявляем еще одну локальную переменную _GET, типа массив, мне кажется
local _GET = {}
-- если vars "не пусто" (скорее всего в нее был ранее помещен массив найденных подстрок из request по первому string.find)
if (vars ~= nil) then
-- тогда мы циклом обходим все найденные в vars пары ключ - значение
-- не могу 100% объяснить, как это работает - это в справочнике по LUA точно есть
for k, v in string.gmatch(vars, "(%w+)=(%w+)&*") do
_GET[k] = v
end
end
-- но с уверенностью на 120% могу сказать, что результатом выполнения этого блока в итоге будет переменная _GET
-- содержащая в себе массив со всеми запрошенными клиентом параметрами
-- если клиент запросил, скажем http://наш_IP/page.html?key1=val1&key3=22
-- то в _GET будет что-то вроде:
-- key1 = val1 и key3 = 22
-- следующим блоком мы докидываем в переменную buf немного HTML текста
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=100\"><button>100% light</button></a> <a href=\"?pin=50\"><button>50% light</button></a> <a href=\"?pin=10\"><button>10% light</button></a> <a href=\"?pin=OFF2\"><button>OFF</button></a></p>";
-- просто разбили его на несколько строк, то есть в итоге в buf будет весь этот текст
-- объявили еще 2 локальных переменных разом _on и _off, поместили в каждую по пустой строке
local _on, _off = "",""
-- ну и дальше проверка параметров в _GET
-- если в _GET параметр pin имеет значение ON1 (строковое)
if(_GET.pin == "ON1")then
-- тогда вызываем метод gpio.write, который, почему-то мне кажется, выставляет на пин led1 единицу (HIGH)
gpio.write(led1, gpio.HIGH);
elseif(_GET.pin == "OFF1")then -- иначе, если в _GET параметр pin имеет значение OFF1
-- тогда вызываем метод gpio.write, который выставляет на пин led1 нолик (LOW)
gpio.write(led1, gpio.LOW);
elseif(_GET.pin == "100")then -- иначе, если в _GET параметр pin имеет значение 100
-- ШИМ на пине led2 с заполнением 1023
pwm.setduty(led2,1023);
-- запустить ШИМ на пине led2
pwm.start(led2);
elseif(_GET.pin == "50")then -- аналогично, но с другим заполнением (50%, видимо)
pwm.setduty(led2,512);
pwm.start(led2);
elseif(_GET.pin == "10")then -- аналогично, но с другим заполнением (10%)
pwm.setduty(led2,10);
pwm.start(led2);
elseif(_GET.pin == "OFF2")then -- по команде OFF2
pwm.stop(led2); -- останавливаем ШИМ
end -- Конец цикла if
-- отправляем клиенту, который послал нам этот запрос, в ответ весь тот текст, что ранее поместили в перменную buf
client:send(buf);
-- закрываем соединение с этим клиентом
client:close();
-- запускаем встроенный сборщик мусора (освобождает всю занятую до этого нашими действиями RAM память)
collectgarbage();
end) -- Конец inline функции "conn:on"
end) -- Конец inline функции "srv:listen"