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

Ошибки при выполнении скрипта

Feo

New member
Доброго дня!
Простейший скрипт 3 файлика.
Опрос 2х датчиков DHT22 и трех 18b20 (в дальнейшем хотелось бы нарастить до 20).
Работает некоторое время и валится с ошибкой "Нехватка памяти" - скрин №1
Перезагрузка модуля не помогает появляется ошибка со скрина №2

Программа таже, ничего не менялось, но с ребута снова не стартует.
Листинги
Код:
WIFI_SSID = "feo"
WIFI_PASS = "********"
MQTT_BrokerIP = "192.168.0.106"
MQTT_BrokerPort = 1883
MQTT_ClientID = "esp-001"
MQTT_Client_user = "user"
MQTT_Client_password = "password"
DHT_PIN = 7 -- задаем пин первого датчика влажности
DHT_PIN2 = 5 -- задаем пин первого датчика влажности

wifi.setmode(wifi.STATION)
wifi.sta.config(WIFI_SSID, WIFI_PASS)
wifi.sta.connect()

local wifi_status_old = 0

tmr.alarm(0, 5000, 1, function()
    print("tmr0 "..wifi_status_old.." "..wifi.sta.status())

    if wifi.sta.status() == 5 then -- подключение есть
        if wifi_status_old ~= 5 then -- Произошло подключение к Wifi, IP получен
            print(wifi.sta.getip())

            m = mqtt.Client(MQTT_ClientID, 120, MQTT_Client_user, MQTT_Client_password)

            -- Определяем обработчики событий от клиента MQTT
            m:on("connect", function(client) print ("connected") end)
            m:on("offline", function(client)
                tmr.stop(1)
                print ("offline")
            end)
            m:on("message", function(client, topic, data)
                print(topic .. ":" )
                if data ~= nil then
                    print(data)
                end
            end)

            m:connect(MQTT_BrokerIP, MQTT_BrokerPort, 0, 1, function(conn)
                print("connected")

                -- Подписываемся на топики если нужно
                --m:subscribe("/var/#",0, function(conn)
                --end)

                tmr.alarm(1, 30000, 1, function()
                    -- Выводим результат работы модуля ds18Init
                    local ds18 = dofile('ds18Init.lua')(6) --   датчики на пине 6 в количестве 3 штук
                    ds18=nil
                             -- выводим результат измерения температуры
                    local ds19 = dofile('ds18run.lua')(6) -- датчики на пине 6 в количестве 3 штук
                    ds19=nil
                   -- print (temp)
                  -- ds18_count=#DS18_ADDR
                   --print(#DS18_ADDR)
                   for i=1,3 do
                   local adr=DS18_ADDR[i]
                   print("№ ",i," ADRR= ",adr:byte(1,8))
                   print(" Temperature= ",temp[i])
                   m:publish("/ESP/DS18_"..i.."/TEMP",temp[i], 0, 0, function(conn) print("sent temp") end)
                   m:publish("/ESP/DS18_ADR_"..i.."/ADR", adr:byte(1)..adr:byte(2)..adr:byte(3)..adr:byte(4)..adr:byte(5)..
                   adr:byte(6)..adr:byte(7)..adr:byte(8), 0, 0, function(conn) print("sent adr") end)
                   end
                              
                    -- Делаем измерения с первого датчика влажности, публикуем их на брокере
                    local status,temp,humi,temp_decimal,humi_decimal = dht.read(DHT_PIN)

                    if (status == dht.OK) then
                        print("Temp: "..temp.." C")
                        print("Hum: "..humi.." %")
                        m:publish("/ESP/DHT/TEMP", temp, 0, 0, function(conn) print("sent") end)
                        m:publish("/ESP/DHT/HUM", humi, 0, 0, function(conn) print("sent") end)
                    end

                     -- Делаем измерения с первого датчика влажности, публикуем их на брокере
                    local status,temp,humi,temp_decimal,humi_decimal = dht.read(DHT_PIN2)

                    if (status == dht.OK) then
                        print("Temp2: "..temp.." C")
                        print("Hum2: "..humi.." %")
                        m:publish("/ESP/DHT2/TEMP", temp, 0, 0, function(conn) print("sent") end)
                        m:publish("/ESP/DHT2/HUM", humi, 0, 0, function(conn) print("sent") end)
                    end

                end)
            end)
        else
            -- подключение есть и не разрывалось, ничего не делаем
        end
    else
        print("Reconnect "..wifi_status_old.." "..wifi.sta.status())
        tmr.stop(1)
        wifi.sta.connect()
    end

    -- Запоминаем состояние подключения к Wifi для следующего такта таймера
    wifi_status_old = wifi.sta.status()
end)

Код:
local M
do
local function addrs(pin)
local addr
ow.setup(pin)
  DS18_ADDR = {}
  ow.reset_search(pin)
  local count = 0
  local N=0
  repeat
    count = count + 1
    addr = ow.search(pin)
    tmr.wdclr()
    if(addr ~= nil) then
        local crc = ow.crc8(string.sub(addr,1,7))
        if crc == addr:byte(8) then
            if (addr:byte(1) == 0x10) or (addr:byte(1) == 0x28) then
                table.insert(DS18_ADDR, addr)
                print('ADDR ADD',N,addr:byte(1,8))
               N=N+1
            end
        end         
    ---  print('ADDR N')
    end
    tmr.wdclr()
  until ((count > 3) )
end

M=addrs
end
return M

Код:
local M
--dofile("ds18Init.lua")

do

local function run(pin)
  temp = {0,0}
  if not DS18_ADDR then print('DS18_ADDR is null') return end
  if not ow then return end
  local j=1
-- print('DS18_ADDR I',i, DS18_ADDR[i])
  ow.setup(pin)
 
  while (DS18_ADDR[j] and DS18_START) do
      local addr=DS18_ADDR[j];
      local present = ow.reset(pin)
      ow.write(pin,0x55,1)
      local i
      for i=1,8 do
        ow.write(pin,addr:byte(i),1)
      end
      ow.write(pin,0xBE,1)
--      print("P="..present)
      local data = nil
      data = string.char(ow.read(pin))
      for i = 1, 8 do
        data = data .. string.char(ow.read(pin))
         tmr.wdclr()
      end
      local crc = ow.crc8(string.sub(data,1,8))
--     print("CRC="..crc)
      if (crc == data:byte(9)) then
       local t = (data:byte(1) + data:byte(2) * 256)
        if (t > 32767) then
          t = t - 65536
        end
        t = (t * 625)/100
        -- Сохраняем значение температуры в глобальной переменной
        --table.insert(temp, t)
        temp[j]=t
       --if LOG then
      -- print(j,"Teeemperature="..(t / 100))
       --end
       -- ListTime[ind+j]={time=tmr.time(),  data=t}
      end
      tmr.wdclr()
      j=j+1
  end
      DS18_START=1
      ow.reset(pin)
      ow.write(pin,0xCC,1)
      ow.write(pin, 0x44, 1)
      tmr.wdclr()
       
  ow.depower (pin)
 
end
M=run
end
return M

Писатель на LUA я начинающий, уверен что что-то очевидное, но уперся и никак.
 

Вложения

  • 577.6 KB Просмотры: 4
  • 582.3 KB Просмотры: 3

nikolz

Well-known member
Доброго дня!
Простейший скрипт 3 файлика.
Опрос 2х датчиков DHT22 и трех 18b20 (в дальнейшем хотелось бы нарастить до 20).
Работает некоторое время и валится с ошибкой "Нехватка памяти" - скрин №1
Перезагрузка модуля не помогает появляется ошибка со скрина №2

Программа таже, ничего не менялось, но с ребута снова не стартует.
Листинги
Код:
WIFI_SSID = "feo"
WIFI_PASS = "********"
MQTT_BrokerIP = "192.168.0.106"
MQTT_BrokerPort = 1883
MQTT_ClientID = "esp-001"
MQTT_Client_user = "user"
MQTT_Client_password = "password"
DHT_PIN = 7 -- задаем пин первого датчика влажности
DHT_PIN2 = 5 -- задаем пин первого датчика влажности

wifi.setmode(wifi.STATION)
wifi.sta.config(WIFI_SSID, WIFI_PASS)
wifi.sta.connect()

local wifi_status_old = 0

tmr.alarm(0, 5000, 1, function()
    print("tmr0 "..wifi_status_old.." "..wifi.sta.status())

    if wifi.sta.status() == 5 then -- подключение есть
        if wifi_status_old ~= 5 then -- Произошло подключение к Wifi, IP получен
            print(wifi.sta.getip())

            m = mqtt.Client(MQTT_ClientID, 120, MQTT_Client_user, MQTT_Client_password)

            -- Определяем обработчики событий от клиента MQTT
            m:on("connect", function(client) print ("connected") end)
            m:on("offline", function(client)
                tmr.stop(1)
                print ("offline")
            end)
            m:on("message", function(client, topic, data)
                print(topic .. ":" )
                if data ~= nil then
                    print(data)
                end
            end)

            m:connect(MQTT_BrokerIP, MQTT_BrokerPort, 0, 1, function(conn)
                print("connected")

                -- Подписываемся на топики если нужно
                --m:subscribe("/var/#",0, function(conn)
                --end)

                tmr.alarm(1, 30000, 1, function()
                    -- Выводим результат работы модуля ds18Init
                    local ds18 = dofile('ds18Init.lua')(6) --   датчики на пине 6 в количестве 3 штук
                    ds18=nil
                             -- выводим результат измерения температуры
                    local ds19 = dofile('ds18run.lua')(6) -- датчики на пине 6 в количестве 3 штук
                    ds19=nil
                   -- print (temp)
                  -- ds18_count=#DS18_ADDR
                   --print(#DS18_ADDR)
                   for i=1,3 do
                   local adr=DS18_ADDR[i]
                   print("№ ",i," ADRR= ",adr:byte(1,8))
                   print(" Temperature= ",temp[i])
                   m:publish("/ESP/DS18_"..i.."/TEMP",temp[i], 0, 0, function(conn) print("sent temp") end)
                   m:publish("/ESP/DS18_ADR_"..i.."/ADR", adr:byte(1)..adr:byte(2)..adr:byte(3)..adr:byte(4)..adr:byte(5)..
                   adr:byte(6)..adr:byte(7)..adr:byte(8), 0, 0, function(conn) print("sent adr") end)
                   end
                             
                    -- Делаем измерения с первого датчика влажности, публикуем их на брокере
                    local status,temp,humi,temp_decimal,humi_decimal = dht.read(DHT_PIN)

                    if (status == dht.OK) then
                        print("Temp: "..temp.." C")
                        print("Hum: "..humi.." %")
                        m:publish("/ESP/DHT/TEMP", temp, 0, 0, function(conn) print("sent") end)
                        m:publish("/ESP/DHT/HUM", humi, 0, 0, function(conn) print("sent") end)
                    end

                     -- Делаем измерения с первого датчика влажности, публикуем их на брокере
                    local status,temp,humi,temp_decimal,humi_decimal = dht.read(DHT_PIN2)

                    if (status == dht.OK) then
                        print("Temp2: "..temp.." C")
                        print("Hum2: "..humi.." %")
                        m:publish("/ESP/DHT2/TEMP", temp, 0, 0, function(conn) print("sent") end)
                        m:publish("/ESP/DHT2/HUM", humi, 0, 0, function(conn) print("sent") end)
                    end

                end)
            end)
        else
            -- подключение есть и не разрывалось, ничего не делаем
        end
    else
        print("Reconnect "..wifi_status_old.." "..wifi.sta.status())
        tmr.stop(1)
        wifi.sta.connect()
    end

    -- Запоминаем состояние подключения к Wifi для следующего такта таймера
    wifi_status_old = wifi.sta.status()
end)

Код:
local M
do
local function addrs(pin)
local addr
ow.setup(pin)
  DS18_ADDR = {}
  ow.reset_search(pin)
  local count = 0
  local N=0
  repeat
    count = count + 1
    addr = ow.search(pin)
    tmr.wdclr()
    if(addr ~= nil) then
        local crc = ow.crc8(string.sub(addr,1,7))
        if crc == addr:byte(8) then
            if (addr:byte(1) == 0x10) or (addr:byte(1) == 0x28) then
                table.insert(DS18_ADDR, addr)
                print('ADDR ADD',N,addr:byte(1,8))
               N=N+1
            end
        end        
    ---  print('ADDR N')
    end
    tmr.wdclr()
  until ((count > 3) )
end

M=addrs
end
return M

Код:
local M
--dofile("ds18Init.lua")

do

local function run(pin)
  temp = {0,0}
  if not DS18_ADDR then print('DS18_ADDR is null') return end
  if not ow then return end
  local j=1
-- print('DS18_ADDR I',i, DS18_ADDR[i])
  ow.setup(pin)

  while (DS18_ADDR[j] and DS18_START) do
      local addr=DS18_ADDR[j];
      local present = ow.reset(pin)
      ow.write(pin,0x55,1)
      local i
      for i=1,8 do
        ow.write(pin,addr:byte(i),1)
      end
      ow.write(pin,0xBE,1)
--      print("P="..present)
      local data = nil
      data = string.char(ow.read(pin))
      for i = 1, 8 do
        data = data .. string.char(ow.read(pin))
         tmr.wdclr()
      end
      local crc = ow.crc8(string.sub(data,1,8))
--     print("CRC="..crc)
      if (crc == data:byte(9)) then
       local t = (data:byte(1) + data:byte(2) * 256)
        if (t > 32767) then
          t = t - 65536
        end
        t = (t * 625)/100
        -- Сохраняем значение температуры в глобальной переменной
        --table.insert(temp, t)
        temp[j]=t
       --if LOG then
      -- print(j,"Teeemperature="..(t / 100))
       --end
       -- ListTime[ind+j]={time=tmr.time(),  data=t}
      end
      tmr.wdclr()
      j=j+1
  end
      DS18_START=1
      ow.reset(pin)
      ow.write(pin,0xCC,1)
      ow.write(pin, 0x44, 1)
      tmr.wdclr()
      
  ow.depower (pin)

end
M=run
end
return M

Писатель на LUA я начинающий, уверен что что-то очевидное, но уперся и никак.
Поищите на форуме мой пример скрипта для работы с файлами
Если кратко то для решения проблемы с памятью надо использовать dofile и сборщик мусора после каждого dofile
 
  • Like
Реакции: Feo

nikolz

Well-known member
и еще если модуль инициализации используется один раз, то его надо убить и вызвать сборку мусора. А лучше сделайте его как функцию еще лучше как вставку dofile
 
  • Like
Реакции: Feo

Feo

New member
Направление ясно, буду разбираться в этом направлении. Есть также совет пользоваться функционалом require.
 

nikolz

Well-known member
Направление ясно, буду разбираться в этом направлении. Есть также совет пользоваться функционалом require.
не надо им пользоваться - это мой совет.
Вообще для экономии памяти не используйте самодельные модули без особой надобности.
 

nikolz

Well-known member
и еще. Так как у Вас нехватка памяти возникает через несколько циклов, то причиной может быть утечка памяти.
Для выяснения этого поставьте вывод на печать остаток свободной памяти.
 

Feo

New member
Разбил программу на модули. модули вызываю require, после выполнения сразу чищу память. Ночь отработала, ошибок нет, работает.
 

nikolz

Well-known member
Разбил программу на модули. модули вызываю require, после выполнения сразу чищу память. Ночь отработала, ошибок нет, работает.
их вообще-то require и загружает.
А как вы раньше загружали модули?
Но использование модулей не экономит память.
 

Feo

New member
dofile раньше пользовался. Не знаю насколько это эквивалентно.
 

nikolz

Well-known member
dofile раньше пользовался. Не знаю насколько это эквивалентно.
если Вы это делали в цикле то возникнет нехватка памяти.
dofile вставляет кусок кода и исполняет.
Если в цикле делать dofile то кусок кода или функция будет многократно грузится в память.
а require загружает модуль(функцию) в память если ее там нет. А Вы обращаетесь к этой функции, вызывая ее.
Но dofile экономит память, если после исполнения загруженного кода вызывать сборщик мусора.
для require надо принудительно удалить ссылку на функцию и вызвать сборщик иначе у Вас модуль инициализации останется в памяти.
Для отладки использования памяти поставьте вывод остатков.
 
  • Like
Реакции: Feo

Feo

New member
Большое спасибо за советы!
я работал как-то так:
Код:
dht = require "dht" ()
package.loaded.dht=nil
 

nikolz

Well-known member
Большое спасибо за советы!
я работал как-то так:
Код:
dht = require "dht" ()
package.loaded.dht=nil
1) вообще-то пишут так:
require "dht"
вместо этого
dht = require "dht" ()
2) после этого
package.loaded.dht=nil
желательно явно вызвать сборщик, так как когда его вызовет VMLua нам неизвестно.
----------------------
Но такой способ явно занимает больше места в памяти и нет смысла его использовать с одноразовыми функциями.
Вы можете сразу в начале основной программы или в init.lua вызвать все что делается один раз например инициализация
потом явно вызвать сборщик потом разместить то что вызывается по прерыванию от таймера.
В результате сначала выполнится инициализация память освободится, а потом будет исполняться остальное.
----------------------------
любой модуль - это создание отдельной таблицы, а на таблицу нужно место
require - это тоже создание таблицы package
------------------------
Все модули которые встроены в луа исполняются из флеш и память фактически не занимают, а Вот Ваши модули грузятся в оперативную память и занимают в два раз больше памяти чем им требуется, так как транслируются в байт код при загрузке.
-------------------------
Рекомендую уделить максимум времени для освоения этих моментов. В результате сможете создавать свои устройства без ограничения размера кода.
 
  • Like
Реакции: Feo

Feo

New member
1) вообще-то пишут так:
require "dht"
вместо этого
dht = require "dht" ()
2) после этого
package.loaded.dht=nil
желательно явно вызвать сборщик, так как когда его вызовет VMLua нам неизвестно.
Могу я попросить Вас показать как правильно явно вызвать сборщик мусора?

Я предполагаю что как-то так:

Код:
print(node.heap().."\r\n")
dht = require "dht" ()
print(node.heap().."\r\n")
package.loaded.dht=nil
collectgarbage()
print(node.heap())
 

nikolz

Well-known member
Могу я попросить Вас показать как правильно явно вызвать сборщик мусора?

Я предполагаю что как-то так:

Код:
print(node.heap().."\r\n")
dht = require "dht" ()
print(node.heap().."\r\n")
package.loaded.dht=nil
collectgarbage()
print(node.heap())
правильно
поставьте print перед ним тоже
нагляднее писать так:
print("1,"..node.heap());
меняете "1" на другие цифры и получаете метки, где выводите принт.
 
  • Like
Реакции: Feo
Сверху Снизу