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
    obuhanoe и 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. ИгорьК

    ИгорьК Гуру

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

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