ESP-8266/ESP32 NodeMCU Lua: азы программирования.

Тема в разделе "ESP8266, ESP32", создана пользователем ИгорьК, 25 июл 2017.

  1. ИгорьК

    ИгорьК Давно здесь Команда форума

    38. Изучаем память 2
    Катализатором продолжения темы выступил baarmaley, путем указания на ошибку в коде сервера, за что огромный респект!

    Собственно, все что можно сказать на эту тему, сказано здесь: https://nodemcu.readthedocs.io/en/latest/lua-developer-faq .

    Переписывать и переводить этот раздел документации смысла нет, но сейчас хочется обратить внимание на следующее.

    Уточним инструмент для работы с памятью.
    В разделе о Lua Registry есть такая штука:
    upload_2019-4-22_14-55-40.png
    То есть, разработчики предлагают нам контролировать регистр путем вычитки всех его записей.
    Попробуем повторить этот код и и посмотреть что будет:
    Код (Lua):
    for k,v in pairs(debug.getregistry()) do print (k,v) end
    upload_2019-4-22_14-58-16.png

    Мы видим две части - индексные записи и записи по ключу. Записи по ключу - отражение деятельности некоторых модулей, которые есть в прошивке. Эти записи всегда остаются постоянными.

    Индексные - результат работы текущей программы.

    Нам интересны только индексные записи, а их увеличивающееся количество в ходе работы скрипта - есть результат (моей) некомпетенции,

    Что делать? Делать инструмент:

    Код (Lua):
    local count = 0
    for _ in ipairs(debug.getregistry()) do  count = count + 1 end
    print(count)
    и наблюдать по ходу работы программы за состоянием индексной части регистра. Растет? Ищем ошибки.

    Итого, на мой взгляд, полезным инструментом, запускаемым для изучения памятных дел будет:
    Код (Lua):
    do
    print("\n\n\n\n\n\n\n\n\n\n\n\n\n=========== _G table: ===========")
    table.foreach(_G, print)
    print("\n===== package.loaded table: =====")
    table.foreach(_G.package.loaded, print)
    local count = 0
    for _ in ipairs(debug.getregistry()) do  count = count + 1 end
    print("=================================")
    print('Reg: '..count, 'Heap: '..node.heap())
    print("=================================")
    end
    И результат:

    upload_2019-4-22_15-13-59.png
     
    Последнее редактирование: 23 апр 2019
    Bop4yN нравится это.
  2. Домосед

    Домосед Нерд

    Решил всё-таки попытаться использовать Вашу библиотеку ds18b20m. В родной библиотеке nodemcu реально слишком много лишнего. Она сжирает почти всю память. Ваша кажется лёгкой и элегантной.
    Но вот я не могу понять, как в Вашей библиотеке вытащить адрес датчика. Это можно сделать?
     
  3. ИгорьК

    ИгорьК Давно здесь Команда форума

    Можно. Мне сейчас сложно ответить более определённо, потому что нахожусь далеко от компьютера и железа.

    У меня несколько библиотек. Некоторые выдают данные в таблицу в формате "адрес датчика = температура".

    Выдрать из таблицы перечень адресов несложно.

    Можно и поправить библиотеку, чтобы адреса выдавались отдельным перечнем

    К сожалению, сейчас я не могу что-то более определённое сказать или помочь.

    В каком формате выдаёт данные та моя библиотека, что вы пользуетесь?
     
  4. Домосед

    Домосед Нерд

    Сейчас просто номер датчика и температура. Было бы очень удобно с адресом, чтобы по адресу можно было бы получать значение температуры.
     
  5. ИгорьК

    ИгорьК Давно здесь Команда форума

    Дайте, пожалуйста, ссылку на библиотеку.
     
  6. Домосед

    Домосед Нерд

  7. ИгорьК

    ИгорьК Давно здесь Команда форума

    Проверьте это:
    Код (Lua):
    local M={}
    M.adrtbl = {}
    M.pin = 4

    function M.addrs()
        ow.setup(M.pin)
        ow.reset_search(M.pin)
        local adr
        repeat
            adr = ow.search(M.pin)
            if(adr ~= nil) then
                table.insert(M.adrtbl, adr)
            end
        until (adr == nil)
        ow.reset_search(M.pin)
        adr = nil
        M.askT()
    end

    function M.askT()
        ow.reset(M.pin)
        ow.write(M.pin, 0xcc, 1)
        ow.write(M.pin, 0x44, 1)
        ow.reset(M.pin)
    end

    function M.readResult(temptabl)  
        local data
        local crc
        local t
        for _, v in pairs(M.adrtbl) do
            ow.reset(M.pin)
            ow.select(M.pin, v)
            ow.write(M.pin,0xBE,1)
            local data = ow.read_bytes(M.pin, 9)
            if (ow.crc8(string.sub(data,1,8)) == data:byte(9)) then
                t = (data:byte(1) + data:byte(2) * 256)
                if (t > 32767) then t = t - 65536 end
                t = t * 625 /10000
                local as = "t"
                for ii = 1, #v do
                    local hx = string.format("%02X", (string.byte(v, ii)))
                    as = as ..hx
                end
                -- temptabl[as] = t
                temptabl[as] = string.format("%.2f",t)
               
            end
        end
        data = nil
        crc = nil
        t = nil
    end

    function M.getTemp(ttable, call, pin, del)
        M.pin = pin or M.pin
        if #M.adrtbl == 0 then
            M.addrs()
        else
            M.askT()
        end
        tmr.create():alarm(del, tmr.ALARM_SINGLE, function (t)
            t:unregister()
            t = nil
            M.readResult(ttable)
            if call then call(ttable) end
        end)
    end
    return M
     
    Применять:

    Код (Lua):
    do
    local now = function()
        local temp = {}  -- Table for temperature
        local pin = 4 -- DS18b20 pin
        local del = 750 -- delay for counting temperature
        local myWork = function(t) -- callback function
            package.loaded["_ds18b20"]=nil
            ds = nil
            table.foreach(t, print)
            print(node.heap())
        end
        ds = require('_ds18b20')
        ds.getTemp(temp, myWork, pin, del )
    end
    now()
    tmr.create():alarm(10000, 1, now)
    end
     
  8. ИгорьК

    ИгорьК Давно здесь Команда форума

    Эта библиотека идентифицирует датчики по адресу, добавляя перед адресом t.

    ds.adrtbl - таблица адресов, но вряд ли она нужна.
     
  9. Домосед

    Домосед Нерд

    Спасибо. Завтра попробую.
     
  10. Домосед

    Домосед Нерд

    Да, это работает. Но, к сожалению, у меня пока не хватает знаний, как выделить для конкретного датчика (например второго) адрес и значение.
    Сейчас (с родной библиотекой) у меня работает так. Сначала сканируются адреса. Потом я в соответствии с каждым адресом присваиваю значение температуры и использую его дальше.
    В Вашем примере я не смог выделить пары адрес-температура.
    Сейчас у меня так с родной библиотекой
    Код (C++):
    function readout(temp)
      if D18b20.sens then
        print("Total number of DS18B20 sensors: ".. #D18b20.sens)
        for i, s in ipairs(D18b20.sens) do
          print(string.format(" sensor #%d address: %s%s",  i, ('%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X'):format(s:byte(1,8)), s:byte(9) == 1 and " (parasite)" or ""))
          print(i .. " --- " .. s)
        end
      end
      for addr, temp in pairs(temp) do
        print(string.format("Sensor %s: %s °C", ('%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X'):format(addr:byte(1,8)), temp))
    -- Присваиваем значения температур в соответствии с датчиками
       if addr == addr_t_in then temp_in = temp
       elseif addr == addr_t_room then temp_room = temp
       elseif addr == addr_t_bak then temp_bak = temp
       elseif addr == addr_t_out then temp_out = temp
       end
      end
    end
    Если не сильно сложно, то может подскажите, как то же сделать с Вашей библиотекой. Если не сможете, то со временем сам разберусь. Всё-равно благодарен за помощь и вообще за само желание нести людям знания.
     
  11. ИгорьК

    ИгорьК Давно здесь Команда форума

    И все таки я не понимаю задачи.
    Сейчас у вас есть таблица, где ключ-значение всегда соответствует конкретному датчику.

    Видимо, есть устройство с несколькими датчиками.

    Загружаете тестовый скрипт и устанавливаете какой датчик имеет какое название. Это соответствие всегда останется неизменным.

    В готовом устройстве даёте команду на опрос датчиков (опрашиваются все).

    После этого у вас есть таблица, где
    table.tXXXXXXXXX - значение температуры каждого.

    Вы из тестового знаете имя каждого и действуете в соответствии с задачами.


    Посмотрел ваш код. Вы создаёте несколько переменных со значением температуры, где к адресу привязываете имя.

    В моем коде у вас уже это будет сделано в виде таблицы. Просто вместо россыпи переменных у вас - таблица. Например table.t12345778 - это комната, table.t87654321 - кухня. etc.
     
    Последнее редактирование: 3 май 2019
  12. Домосед

    Домосед Нерд

    То есть, для получения значения температуры нужно просто указать, A = table.t28FFD47551170413 (адрес после t - адрес датчика, который определился при запуске скрипта)
    Так не получается.
     
  13. Домосед

    Домосед Нерд

    Вроде разобрался маленько :) Спасибо
     
  14. ИгорьК

    ИгорьК Давно здесь Команда форума

    Зачем? Она у вас уже есть - манипулируйте сразу ей :)
    Для чего лишнее присваивание?
     
  15. ИгорьК

    ИгорьК Давно здесь Команда форума

    Таблицы и каллбэки - вся суть Lua от NodeMcu.
    Работайте сразу с таблицей температур.
    Что вы хотите с температурами делать дальше?
     
  16. Домосед

    Домосед Нерд

    Да это я так, к примеру привёл. Понятно, что присваивание не нужно.

    Проверка на заданные значения и управление клапанами и насосами. :) Водяное охлаждение для майнинговой фермы. Ну всё это завязываю на Home Assistant через MQTT с возможностью управлять вручную и получать уведомления в telegram. Но знаний синтаксиса не хватает, а время поджимает. Надо до отпуска автоматику запустить. А уже потом буду оптимизировать и улучшать.
    Конечно больше хобби, чем необходимость :) На ардуино год работает. Хочется обновить.
     
  17. ИгорьК

    ИгорьК Давно здесь Команда форума

    Это проблема. Сложно менять мышление Ардуино.

    Это (программно) работы на 15 минут. К сожалению, со смартфона ничего путного я вам не напишу.
    Глобально: в каллбэке myWork пишете проверку условий и действия. И все

    Я предпочитаю ничего не завязывать, а делать автономные устройства. По протоколу они получают лишь команды на изменения режимов работы. И то - это исключение, чем правило.

    В частности, "вручную" у меня работают лишь включение отопления гаража, потому что нет никакого алгоритма понять когда оно мне нужно и установка интервалов полива в теплице - не знаю пока каков он.

    Остальное работает без участия любых "умных домов", а лишь шлёт на них отчёты о состоянии.
     
  18. ИгорьК

    ИгорьК Давно здесь Команда форума

    Посмотрите эту тему, что-то полезное найдёте там.
     
  19. Домосед

    Домосед Нерд

    Да я уже почти всё сделал. Стендовые испытания веду. Вот осталось совсем чуток управление давлением в системе охлаждения доделать. Думаю, что сегодня уже будет готово.

    Это да. Потому система должна не только управляться, но и работать автономно в заданных режимах. Ну а ручное управление и возможность изменения диапазона - это как бонус. Потому приходится продумывать всё с учётом автономности.
     
    ИгорьК нравится это.
  20. ИгорьК

    ИгорьК Давно здесь Команда форума

    Когда-то делал такую возможность для установки температуры в погребе. И что?
    За три года так ни разу и не поменял :)

    Да там вообще можно вручную отопление, охлаждение включать, принудительно что-то. Уж и не помню.
    Так ни разу...