• Система автоматизации с открытым исходным кодом на базе esp8266/esp32 микроконтроллеров и приложения IoT Manager. Наша группа в Telegram

Lua скрипты и модули

pvvx

Активный участник сообщества
Проверил cпоследней Lua– всё нормально со вторым UART. Отключают правильно. Значит что-то ещё…
ESP8266 Pin List 05.11.2014.XLSX RX1 - GPIO8, RX0 - GPIO3
 
Последнее редактирование:

skylocker

Member
Блииин, мой моСк скрипит, переваривая все это..
Я понял, что пины могут работать в разных режимах (function) и выбор режима осуществляется программно или аппаратно. Дальше - в дебри UART1 не пошел, ибо не выведены у меня эти пины.

Но у меня возник вопрос - то, что у меня GPIO16 (XPD_DCDC) висит в воздухе - это очень плохо? На что это может влиять? На него нормально нужно VCC подавать?
На CH_PD я подключил VCC - правильно ведь?
 

pvvx

Активный участник сообщества
@skylocker На модуль типа 01 давал, что происходит на его пинах при старте там: http://esp8266.ru/forum/threads/ne-rabotaet-modul-esp8266.13/#post-46
Как будет работать boot описано в xls, приведенной выше, на последней странице.
Как я понял, у писателей Lau, используется собственная плата подключения модуля со всеми i/o.
 
Последнее редактирование:

skylocker

Member
Кажется, я понял, почему зависает скрипт - банально не хватает памяти.. ((
После инициализации (загрузка скрипта + коннект к точке доступа) heap уменьшается до 10000, при http-запросе занимается еще около 2-3 кб (потом освобождаются)

Есть, может, у кого-то какие-то советы - что с этим делать, как оптимизировать lua-скрипты?
 

Victor

Administrator
Команда форума
Кажется, я понял, почему зависает скрипт - банально не хватает памяти.. ((
После инициализации (загрузка скрипта + коннект к точке доступа) heap уменьшается до 10000, при http-запросе занимается еще около 2-3 кб (потом освобождаются)

Есть, может, у кого-то какие-то советы - что с этим делать, как оптимизировать lua-скрипты?
Попробуйте разбить скрипт на несколько файлов, в соответствии с выполняемыми задачами. Пока скрипт в файле во флеш памяти, он не занимает RAM. Немного поможет.
 

skylocker

Member
К слову, пробовал подавать VCC на RST (джампер припаял) - эффекта ноль, при подаче питания на rst вообще не воркает ((
 

skylocker

Member
Попробуйте разбить скрипт на несколько файлов, в соответствии с выполняемыми задачами. Пока скрипт в файле во флеш памяти, он не занимает RAM. Немного поможет.
Спасибо за отклик.
Вопрос 1:
Правильно я понимаю, что как только я единожды сделаю dofile('xxx'), подгрузив некий функционал, память отъестся и более не освободится?

Вопрос 2:
Есть ли какая-то разница (с точки зрения отбора RAM) между:
1. tmr.alarm(0, 30000, 1, function() do_something end)
и
2. function func() do_something end
tmr.alarm(0, 30000, 1, func())
?

Вопрос 3:
можно ли управляемо выгружать из памяти куски кода (например, работу с DNS - один раз выполнили, в переменную сохранили и выкинули из RAM)?
 

Victor

Administrator
Команда форума
На первый вопрос - да.
На второй - попробуйте так и так и замеряйте heap. я не проверял.
На третий - нет (исходя из той информации, которой владею я)
Код прошивки NodeMCU закрыт, так что, кроме разработчиков, никто точно не скажет.
 

Vasiks

Member
Новости ну очень радостные.

Пример http сервера : http://10.10.10.xxx/?mode=[on,off,party]&key='api_key'

Код:
function HTTPd()
  print('start http serv')
  srv=net.createServer(net.TCP, 5)
  srv:listen(80,function(conn)
    conn:on("receive",function(conn,payload)
      print(payload)

      if string.find(payload, "key="..c_api_key) then
        msg = "key_ok"
        if string.find(payload,"mode=on") then
          on()
        else
          if string.find(payload,"mode=off") then
            tmr.stop()
            off()
          else
            if string.find(payload, "mode=party") then
              party(200)
            end
          end
        end
      else
        msg = "error_key"
      end
      conn:send("<html><head></head><body><h1> mode=[on,off,party] key='api_key' </h1><p>"..msg.."</p></body></html>")
    end)
    conn:on("sent",function(conn) conn:close() end)
  end)
end
Хочю функцию сериализации/десериализации мож тыкнете. Есть что то по приятнее чем string.find(payload, "substr")? Видал модули JSON но мне показался слишком тяжелым. Даже загрузить не смог.

Так же интересует вопрос отвечают ли датчики по широковещательному адресу( и как реализовать на nodeMCU), нужно определить есть ли еше кто в текущей подсети.
Пытаюсь повторить Ваш проект: http://geektimes.ru/post/242366/
Есть вопросы: что такое api_key и зачем он нужен? Файлы проекта нужно все заливать? Порядок заливки в модуль имеет значение?
Вы как-то улучшили\доработали схему?
 

NeoroN

Member
вот еще веб сервер - с парсингом запроса и переменных в массив _GET как в PHP
Код:
wifi.setmode(wifi.SOFTAP);
wifi.ap.config({ssid="test",pwd="12345678"});
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> Hello, NodeMcu.</h1><form src=/>Turn GPIO2 <select name=pin onchange=\"form.submit()\">";
          print("\nMethod: "..method);
          print("Path: "..path);
          local _on,_off = "",""
          if(_GET.pin == "ON")then
                 _on = " selected=true";
                 gpio.write(4, gpio.HIGH);
          elseif(_GET.pin == "OFF")then
                 _off = " selected=true";
                 gpio.write(4, gpio.LOW);
          end
          buf = buf.."<option".._on..">ON</opton><option".._off..">OFF</option></select></form>";
          client:send(buf);
          client:close();
          collectgarbage();
     end)
end)
вот еще функции обработки строк для веб сервера
Код:
function urlEncode(str)
    if (str) then
        str = string.gsub (str, "\n", "\r\n")
        str = string.gsub (str, "([^%w ])",
            function (c) return string.format ("%%%02X", string.byte(c)) end)
        str = string.gsub (str, " ", "+")
    end
    return str
end
function urlDecode(str)
    local str;
    str = string.gsub (str, "+", " ");
    str = string.gsub (str, "%%(%x%x)", function(h) return string.char(tonumber(h,16)) end);
    str = string.gsub (str, "\r\n", "\n");
    return str
end
 

NeoroN

Member
Авторизация для веб сервера тоже просто делается, вставить код в начале где нибудь(до local _GET = {}):
Код:
          local _, _, auth = string.find(request, "%cAuthorization: Basic ([%w=\+\/]+)");--Authorization:
          if (auth == nil or auth ~= "dXNlcjoxMjM0")then --user:1234
               client:send("HTTP/1.0 401 Authorization Required\r\nWWW-Authenticate: Basic realm=\"NodeMCU\"\r\n");
               client:close();
               return;
          end
dXNlcjoxMjM0 это user:1234 в base64
 

Victor

Administrator
Команда форума
NTP клиент.
Проверил у себя - работает. Запускал отдельным файлом ntp-run.lua
При повторном запуске модуль перезагружается.
Периодический запуск по таймеру не пробовал.
Код:
dofile('ntp-run.lua')

> 23:38:22
Код:
loadfile("ntp.lua")():sync(function(T) 
     print(T:show_time()) 
     end)
Код:
-- -----------------------------------------------------------------------------------
-- for a continuous run:
-- TIME=loadfile("ntp.lua")()
-- TIME:run(timer,updateinterval,syncinterval,[ntp-server])
-- TIME.hour TIME.minute TIME.second are updated every 'updateinterval'-seconds
-- NTP-server is queried every 'syncinterval'-seconds
--
-- a one-time run:
-- loadfile("ntp.lua")():sync(function(T) print(T:show_time()) end)
--
-- config:
-- choose a timer for udptimer
-- choose a timeout for udptimeout
--    timer-function to close connection is needed - memory leaks on unanswered sends :(
-- set tz according to your timezone
-- choose a NTP-server near you and don't stress them with a low syncinterval :)
-- -----------------------------------------------------------------------------------

return({
     hour=0,
     minute=0,
     second=0,
     lastsync=0,
     ustamp=0,
     tz=1,
     udptimer=2,
     udptimeout=1000,
     ntpserver="193.170.62.252",
     sk=nil,
     sync=function(self,callback)
          -- print("SYNC " .. self.ustamp .. " " .. self.ntpserver)
          -- request string blindly taken from http://arduino.cc/en/Tutorial/UdpNTPClient ;)
          local request=string.char( 227, 0, 6, 236, 0,0,0,0,0,0,0,0, 49, 78, 49, 52,
          0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
          )
          self.sk=net.createConnection(net.UDP, 0)
          self.sk:on("receive",function(sck,payload)
               -- tmr.stop(self.udptimer)
               sck:close()
               self.lastsync=self:calc_stamp(payload:sub(41,44))
               self:set_time()
               if callback and type(callback) == "function" then
                    callback(self)
               end
               collectgarbage() collectgarbage()
               -- print("DONE " .. self.ustamp)
          end)
          self.sk:connect(123,self.ntpserver)
          tmr.alarm(self.udptimer,self.udptimeout,0,function() self.sk:close() end)
          self.sk:send(request)
     end,
     calc_stamp=function(self,bytes)
          local highw,loww,ntpstamp
          highw = bytes:byte(1) * 256 + bytes:byte(2)
          loww = bytes:byte(3) * 256 + bytes:byte(4)
          ntpstamp=( highw * 65536 + loww ) + ( self.tz * 3600)  -- NTP-stamp, seconds since 1.1.1900
          self.ustamp=ntpstamp - 1104494400 - 1104494400         -- UNIX-timestamp, seconds since 1.1.1970
          -- print(string.format("NTP: %u",ntpstamp))
          -- print(string.format("UIX: %u",self.ustamp))
          return(self.ustamp)
     end,
     set_time=function(self)
          self.hour = self.ustamp % 86400 / 3600
          self.minute = self.ustamp % 3600 / 60
          self.second = self.ustamp % 60
          -- print(string.format("%02u:%02u:%02u",hour,minute,second))
     end,
     show_time=function(self)
          return(string.format("%02u:%02u:%02u",self.hour,self.minute,self.second))
     end,
     run=function(self,t,uinterval,sinterval,server)
          if server then self.ntpserver = server end
          self.lastsync = sinterval * 2 * -1 -- force sync on first run
          tmr.alarm(t,uinterval * 1000,1,function()
               self.ustamp = self.ustamp + uinterval
               self:set_time()
               -- print(self:show_time())
               if self.lastsync + sinterval < self.ustamp then
                    self:sync()
               end
          end)
     end
})
 

alexhi

Member
Пытаюсь повторить Ваш проект: http://geektimes.ru/post/242366/
Есть вопросы: что такое api_key и зачем он нужен? Файлы проекта нужно все заливать? Порядок заливки в модуль имеет значение?
Вы как-то улучшили\доработали схему?
Visiks ,а что вы использовали в качестве AC/DC 5V в этом проекте?
 

Vasiks

Member

Vasiks

Member
Помогите со скриптом. Нужно чтобы при наличии на GPIO_0 логической единицы GPIO_2 переходил в состояние "HIGHT". Пока накидал это:
Код:
Relay=4   --GPIO_2 как выход
Button=3  --GPIO_0 как вход
   
    gpio.mode(Relay, gpio.OUTPUT)
    gpio.mode(Button, gpio.INPUT)
    gpio.write(Relay, gpio.LOW)

    tmr.delay(1000000)
    gpio.write(Relay, gpio.HIGH)
    tmr.delay(1000000)
    gpio.write(Relay, gpio.LOW)
    print(gpio.read(Relay))
    print(gpio.read(Button))

function on()
  
     if gpio.read(Button) == "HIGH" then  gpio.write(Relay, gpio.HIGH) end
   
    end
Задержку сделал чтоб было понятно, что код хоть как-то выполняется.
Пин зажигается, гаснет. Из отладочной инфы видно, что состояние пина-кнопки считывается корректно, при подаче питания - единица, при замыкании на gnd - ноль.
Но видимо условие не верно написано, поэтому Relay не реагирует на Button.
Подскажите, как правильно накодить?
Пробовал так:
Код:
function on()
 
     if gpio.read(Button) == 1 then  gpio.write(Relay, gpio.HIGH) end
  
    end
И так:
Код:
function on()
 
     if (gpio.read(Button)) == 1 then  gpio.write(Relay, gpio.HIGH) end
  
    end
В идеале должно быть так, при нажатии на кнопку первый раз - Relay включается, при нажатии следующий раз - выключается, и т.д.
 

Victor

Administrator
Команда форума
Очень трудно в Рождество анализировать скрипты...
Может быть поэтому я не увидел нигде вызов функции on?
 

Vasiks

Member
Очень трудно в Рождество анализировать скрипты...
Может быть поэтому я не увидел нигде вызов функции on?
Точно!
А как сделать, чтоб этот скрипт всегда выполнялся? И после перезапуска модуля тоже?
 
Последнее редактирование:

skylocker

Member
Уважаемые знатоки, нужна помощь.

Все наверняка уже столкнулись с нехваткой RAM при наличии виртуальной машины lua в памяти )
Я уже спрашивал про то, как можно выгрузить из памяти часть ненужного кода. Ответ был "код закрыт" и "никак", однако, судя по официальному примеру работы с DS18b20 на http://www.nodemcu.com/index_en.html память можно и нужно освобождать так:
ds18b20 =nil -- освобождаем память, занимаемую переменной
package.loaded["ds18b20"]=nil -- освобождаем память, занимаемую куском кода (библиотекой, которую мы загружали reqire("..."))

Однако, в процессе тестирования я нашел один момент, который не дает мне пока возможности использовать эти фичи... ((
А именно - heap не освобождается до тех пор, пока не активируется интерпретатор (субъективное мнение - событие в коде посмотреть не могу - в Си не силен, функции, как насильно почистить мусор/освободить heap тоже не знаю).

Вот пример - доказательство того, что HEAP не освобождается при удалении переменных даже после большого таймаута при использовании в программе:

print(node.heap()) --19864
sk=net.createConnection(net.TCP, 0)
sk:eek:n("receive", function(sck, c) print('answer length is '..#c) end)
sk:connect(80, "api.skylocker.ru")
sk:send("GET /get/test_str/ HTTP/1.1\r\nHost: api.skylocker.ru\r\n\r\n")
print(node.heap()) --18600
sk:close() sk=nil sck=nil print(node.heap()) tmr.delay(2000000) print(node.heap()) tmr.delay(5000000) print(node.heap()) --выдает 17968, через 2 сек 17928, через 5 сек снова 17928

затем вываливается в консоль и стоит сразу сделать print(node.heap()) - выдает 19448

Может, кто-то знает (или в Си-коде высмотрит функцию), как принудительно вызвать Lua-сборщик мусора, чтобы после var=nil он HEAP очистил?

Очень нуна ))
 
Сверху Снизу