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

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

Victor

Administrator
Команда форума
ESPlorer часто использует куски LUA кода для выполнения некоторых операций (cat, save file to ESP и т.д.)
В конце выполнения кроме обнуления переменных я "обниляю" и обычные функции. После этого запускаю стандартную команду "collectgarbage()"
Поэтому рекомендую не делать так
Код:
sk:on("receive", function(sck, c) print('answer length is '..#c) end)
а делать так
Код:
function func1
print('func1')
end
sk:on("receive", func1)
...
...
func1=nil
collectgarbage()
как-то так...
 

Victor

Administrator
Команда форума
Точно!
А как сделать, чтоб этот скрипт всегда выполнялся? И после перезапуска модуля тоже?
Поместите код в init.lua или, что более красиво и надежно, поставьте в инит.луа настройку сети а потом по таймеру вызов другого файла с кодом для GPIO
 

skylocker

Member
Случайно увидел такой проект:
semi-HTTP-compliant lua libary to download files and send GET requests
Там в файле example.lua используется функция collectgarbage() как раз после освобождения памяти. Может, это оно?
Спасибо за отклик. Вроде бы похоже и на collectgarbage() из консоли не ругается, но в моем примере не работает:

заменил последнюю строчку на
sk:close() sk=nil sck=nil print(node.heap()) collectgarbage() print(node.heap()) tmr.delay(2000000) print(node.heap()) collectgarbage() print(node.heap()) tmr.delay(5000000) print(node.heap())

запустил, увидел в самом начале (перед выполнением) цифру 19608, а после выполнения всего - такой ответ:
18544
17784
17784
17728
17784
17728
>
> print(node.heap())
19344

Последнее - в интерпретаторе.. ((
 

skylocker

Member
В конце выполнения кроме обнуления переменных я "обниляю" и обычные функции. После этого запускаю стандартную команду "collectgarbage()"
Спасибо, попробую.

Но почему в процессе работы программы не видно результатов collectgarbage()?
 

Victor

Administrator
Команда форума
Спасибо, попробую.

Но почему в процессе работы программы не видно результатов collectgarbage()?
пока вы не разбили код на функции у вас все переменные глобальные. используйте именованные функции и локальные переменные. Обниляйте последовательно - локальные переменные в конце функции, затем по окончании работы функции онбиляйте и ее. Глобально используйте только если действительно необходимо.
collectgarbage() эффективен, когда вы обниляете большие строковые переменные и/или функции.
Код:
print(node.heap().."\r\n")
s="abc0123456789abc\r\n";
print(s)
print(node.heap().."\r\n")
s=nil
collectgarbage()
print(node.heap())
 

skylocker

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

skylocker

Member
Чего-то не особо получилось.. ((

Вот лог:
> print(node.heap())
19864
> function func1(sck, c) print('answer length is '..#c) end
> print(node.heap())
19192
> sk=net.createConnection(net.TCP, 0)
> sk:eek:n("receive", func1)
> sk:connect(80, "api.skylocker.ru")
> sk:send("GET /get_data/test_str/ HTTP/1.1\r\nHost: api.skylocker.ru\r\n\r\n")
> answer length is 224
print(node.heap())
18584
> sk:close() sk=nil sck=nil func1=nil print(node.heap()) collectgarbage() print(node.heap()) tmr.delay(2000000) print(node.heap()) collectgarbage() print(node.heap()) tmr.delay(5000000) print(node.heap())
17808
17808
17768
17808
17768
> print(node.heap())
19400

Замечу, что после возврата в интерпретатор память освобождается..
 

Vasiks

Member
Почему, когда считываю состояние пина, то он вырубается? Делаю:
Код:
gpio.read(4)
и после этой строчки пин из HIGH переходит в LOW. Как считывать состояние не меняя этого состояния?
 

skylocker

Member
У меня тоже глюк при работе с GPIO или с самим Lua - я уже минут 30 зависаю, не знаю, куда копать:

Код:
s=net.createServer(net.TCP, 30)
s:listen(80, function(c)
    c:on("receive", function(c,pl)
        local i=adc.read(0)
        i=i*123/100
        print(i)
        gpio.mode(3,gpio.INPUT)
        local v=gpio.read(3)
        print(v)
        c:send("ADC:"..i.."\nGPIO(3):???\nTMR:"..tmr.now().." MEM:"..node.heap())
        c:on("sent",function(c) c:close() end)
        i,v=nil,nil
    end)
end)
Замечу, что работает нормально - в консоль вываливает значение ADC (переменная i) и GPIO0 (по новой таблице, 3 индекс, у меня переменная v).
Даже с ADC проблем нет, хотя в мануале написано было "The ADC cannot be used when the chip is transmitting", но там, вероятно, речь шла непосредственно о работе радиотракта (?).

Проблема (зависание и ребут SoC) возникает сразу после попытки вывести в HTTP-ответ значения переменной v - стоит изменить строку
c:send("ADC:"..i.."\nGPIO(3):???\nTMR:"..tmr.now().." MEM:"..node.heap())
на
c:send("ADC:"..i.."\nGPIO(3):"..v.."\nTMR:"..tmr.now().." MEM:"..node.heap())

Что тут не так? Я честно смотрю в мануал - там сказано, что gpio.read() возвращает number:0 - low, 1 - high, в консоли вижу, что v=1
Куда копать?
 
Что тут не так? Я честно смотрю в мануал - там сказано, что gpio.read() возвращает number:0 - low, 1 - high, в консоли вижу, что v=1
Куда копать?
Копать в node.heap(). Вот так работает:
Код:
s=net.createServer(net.TCP, 30)

s:listen(80, function(c)
  c:on("receive", function(c,pl)
  local i=adc.read(0)
  i=i*123/100
  print(i)
  gpio.mode(5,gpio.INPUT)
  local v=gpio.read(3)
  print(v)
   local h=node.heap()
   print(h)
  c:send("ADC:"..i.."\nGPIO(5):"..v.."\nTMR:"..tmr.now().." MEM:"..h)
  c:on("sent",function(c) c:close()  end)
  i,v,h=nil,nil,nil
  end)
end)
 

skylocker

Member
Копать в node.heap(). Вот так работает:
Код:
s=net.createServer(net.TCP, 30)

s:listen(80, function(c)
  c:on("receive", function(c,pl)
  local i=adc.read(0)
  i=i*123/100
  print(i)
  gpio.mode(5,gpio.INPUT)
  local v=gpio.read(3)
  print(v)
   local h=node.heap()
   print(h)
  c:send("ADC:"..i.."\nGPIO(5):"..v.."\nTMR:"..tmr.now().." MEM:"..h)
  c:on("sent",function(c) c:close()  end)
  i,v,h=nil,nil,nil
  end)
end)
Боюсь, Вы так и не ответили. В описании node.heap (нет ни слова про то, что нужно писать в переменную, только то, что "returns number"). Ваш способ похож на "метод научного тыка", без обид :)

Таким же способом я нашел, что и вот так будет работать:
Код:
s=net.createServer(net.TCP, 30)
s:listen(80, function(c)
    c:on("receive", function(c,pl)
        local i=adc.read(0)
        i=i*123/100
        print(i)
        gpio.mode(0,gpio.INPUT)
        local v=gpio.read(0)
        print(v)
        print(tmr.now())
        c:send("ADC:"..i.." GPIO(3):"..v.." MEM:"..node.heap())
        c:on("sent",function(c) c:close() end)
        i,v=nil,nil
        collectgarbage()
    end)
end)
У меня подозрения, что это какой-то баг nodeMCU или моя невнимательность (но я просто не вижу - где)..
 
Да без обид. В "сырых" (без тестирования) проектах данный метод незаменим))) Можно бесконечно читать доки. К сожалению исходники nodemcu недоступны?
 

skylocker

Member
Почему, когда считываю состояние пина, то он вырубается? Делаю:
gpio.read(4)
и после этой строчки пин из HIGH переходит в LOW. Как считывать состояние не меняя этого состояния?
Посмотрите в мануал к gpio.mode(), может, поможет - там речь идет о состоянии PULLUP-резистрора:

gpio.mode(pin, mode, pullup)
pullup: gpio.PULLUP or gpio.FLOAT, default: gpio.FLOAT
 
Работа GPIO в NodeMCU действительно не очевидна. В любом случае INPUT ЛУЧШЕ использовать с gpio.PULLUP, т.е. с подтягивающим (к питанию) внутренним сопротивлением! Если кнопка - то коммутировать на GND. Вход не будет "болтать"... А модуль очень чувствителен.
GND - коснитесь пальцем - модуль в reset.
GPIO0 - используется бутлоадером - лучше как вход (тем более без PULLUP) не использовать.
GPIO2 - заземлите и включите - вообще "крыша" у модуля сходит!!!
При GPIO16 - он же RESET - я вообще молчу.
 

skylocker

Member
Работа GPIO в NodeMCU действительно не очевидна. В любом случае INPUT ЛУЧШЕ использовать с gpio.PULLUP, т.е. с подтягивающим (к питанию) внутренним сопротивлением! Если кнопка - то коммутировать на GND. Вход не будет "болтать"... А модуль очень чувствителен.
GND - коснитесь пальцем - модуль в reset.
GPIO0 - используется бутлоадером - лучше как вход (тем более без PULLUP) не использовать.
GPIO2 - заземлите и включите - вообще "крыша" у модуля сходит!!!
При GPIO16 - он же RESET - я вообще молчу.
Не соглашусь. В корне.
Ибо, если подключать кнопку правильно (с подтягиванием внешним резистором - к VCC или земле) - работать будет 100% корректно. А уж если еще и с фильтром (см. инвертирующий триггер Шмитта + конденсатор), то аппаратно и от дребезга контактов можно избавиться.

Далее, ни разу не замечал того, что вы говорите про "палец на GND".. Может, у меня пальцы не такие? :)
Про GPIO2 расскажите подробнее (лучше - с картинкой с осциллографа при загрузке), а то так звучит, мягко говоря, очень поверхностно.

А что Вы имеете против "GPIO16 на RESET"? В мануале описано, что это нужно, если Вы хотите использовать DeepSleep-режим. И никаких глюков лично я тут не замечал - работает (проверял на новой ревизии ESP-07 с 16 пинами и на ESP-12).

В общем, мой мессадж такой - если пишете, то, плз, пишите детально - что именно делаете и что, на Ваш взгляд, работает не так.
И вот еще - проверьте, все ли нормально пропаяли )
 
Про GPIO2. ESP-01
Прошивка NodeMCU 2015 года или последняя 2014.
Без питания подключаем GPIO2 к GND. Включаем питание.
Непрерывно горит синий светодиод (ну и красный) и в COM порт что-то постоянно посылается.
У вас не так?
 

Vasiks

Member
Так что с чтением состояния GPIO? Получается не реально считать не отправляя пин в LOW?
 

skylocker

Member
Про GPIO2. ESP-01
Прошивка NodeMCU 2015 года или последняя 2014.
Без питания подключаем GPIO2 к GND. Включаем питание.
А зачем Вы при загрузке на GPIO2 подаете LOW?
В комментах к NodeMCU-devkit, например, черным по белому написано "On every boot/reset/wakeup: GPIO15 MUST keep LOW, GPIO2 MUST keep HIGH".
Умные люди тут наверняка даже ссылку на ESP8266_Pin_List_141105 и, возможно, даже объяснят, почему именно GPIO2 MUST keep HIGH (насколько я понял, MTDO, GPIO0 и GPIO2 совместно образуют 3 бита, которые определяют 8 разных конфигов загрузки; подавая LOW на GPIO2 Вы выбираете "remapping" вместо "UART Boot"; что такое remapping пусть лучше объяснят знатоки).
 

skylocker

Member
Так что с чтением состояния GPIO? Получается не реально считать не отправляя пин в LOW?
С чего бы вдруг? Все работает. Просто подтяжку используйте - программную (при инициализации порта указывайте pullup = gpio.PULLUP) или аппаратную (резистор к питанию).
 
Сверху Снизу