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

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

  1. petr0vsk

    petr0vsk Нерд

    У меня вопрос - почему пример из документации ни чего не отдает в браузер?
    Код (Text):

    -- server listens on 80, if data received, print data to console and send "hello world" back to caller
    -- 30s time out for a inactive client
    sv = net.createServer(net.TCP, 30)
    function receiver(sck, data)
      print(data)
      sck:close()
    end
    if sv then
      sv:listen(80, function(conn)
        conn: on("receive", receiver)
        conn:send("<h1> Hello, NodeMCU!!! </h1>")
      end)
    end
    То есть в консоль он отдает данные по GET запросу, а с браузером рвет соединение и ни чего не отдает. При этом если соеденится по telnet то "<h1> Hello, NodeMCU!!! </h1>" видно.
    Я попытался в Вашем примере: (12. Маленький сервер) убрать чтение файла и оставить вместо цикла conn:send("<h1> Hello, NodeMCU!!! </h1>") - тот же результат т.е. в браузере инфа не отображается. Где-то у меня серьезный пробел в скудных знаниях. Если поясните - буду очень благодарен.
     
    Последнее редактирование: 28 апр 2018
  2. ИгорьК

    ИгорьК Гуру

    Начнем с картинки:


    [​IMG]
     
  3. ИгорьК

    ИгорьК Гуру

    Ок. Я yже писал здесь, что этот код - КОСЯК!

    Надо так:
    Код (Lua):
    do
       srv = net.createServer(net.TCP)
       function receiver(sck, data)
         local function closec()
           sck:close()
         end
         local function send()
          sck:send("<h1> Hello, NodeMCU!!!</h1>")
         end
         sck:on("sent", closec)
         send()
       end
       srv:listen(80, function(conn)
        conn:on("receive", receiver)
       end)
    end
     
     
    Последнее редактирование: 28 апр 2018
    petr0vsk нравится это.
  4. ИгорьК

    ИгорьК Гуру

    Вот вам самый краткий код сервера:
    Код (Lua):
    do
    srv = net.createServer(net.TCP)
    function receiver(sck, data)
        print(data)
        sck:send("<h1> Hello, NodeMCU!!! </h1>")
        sck:on("sent", function()
            sck:close()
        end)
    end
    srv:listen(80, function(conn)
      conn:on("receive", receiver)
    end)
    end
    upload_2018-4-28_16-25-33.png
     
    tpolimer и petr0vsk нравится это.
  5. ИгорьК

    ИгорьК Гуру

    Или совсем-совсем просто:
    Код (Lua):
    do
    -- Создаем сервер
    srv = net.createServer(net.TCP)

    -- Даем серверу команду слушать 80 порт
    -- Как только происходит соединение
    -- вызывается анонимная функция с передачей
    -- ей параметра соединения "conn": "conn" возникает в момент соединения
    srv:listen(80, function(conn)
        -- Функция готовит реакцию на два события "conn"
        -- (1) По получению данных от клиента - печать и отправка
        -- путем вызова анонимной функции
        conn:on("receive", function (sck, data)
            print(data)
            sck:send("<h1> Hello, NodeMCU!!! </h1>")
        end)
        -- (2) По отправке данных клиенту - рассоединение  с ним
        -- тоже анонимная функция
        conn:on("sent", function(sck)
            sck:close()
        end)
    end)
    end
    Без комментариев:
    Код (Lua):
    do
    srv = net.createServer(net.TCP)
    srv:listen(80, function(conn)
        conn:on("receive", function (sck, data)
            print(data)
            sck:send("<h1> Hello, NodeMCU!!! </h1>")
        end)
        conn:on("sent", function(sck)
            sck:close()
        end)
    end)
    end
     
    Последнее редактирование: 22 апр 2019
    tpolimer и petr0vsk нравится это.
  6. Вечер добрый. Вопрос есть такого плана, как записать параметры датчиков DS18B20 в таблицу?
    Вот такой код, считывает из стандартной библиотеки DS температуру датчиков:
    Код (C++):
    local pin = 4
    ds18b20.setting({}, 9)
    ds18b20.setup(pin)
    ds18b20.read(
        function (ind,rom,res,temp,tdec,par) pn=ind
                   print(ind,string.format("%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X",string.match(rom,"(%d+):(%d+):(%d+):(%d+):(%d+):(%d+):(%d+):(%d+)")),res,temp,tdec,par)
         end,{},0x28);
       
    При запуске выдается следующее:
    1 28:FF:8A:CF:63:15:01:91 9 26.5 500 0
    2 28:FF:3A:32:16:15:03:54 12 26.25 250 0
     
  7. ИгорьК

    ИгорьК Гуру

    Какого вида таблицу вы хотите, что она должна содержать, как?

    То есть сначала определитесь с устройством таблицы, чтобы я мог вам помочь

    Вот мой вариант с моей библиотекой.
    https://bitbucket.org/igorkkk/ds18b20
     
  8. ИгорьК

    ИгорьК Гуру

    Немного о таблицах.
    Задачу предложил SmileOfFortune в посте выше
    Речь о стандартном модуле ds18b20.

    Теория.
    Создадим таблицу
    Код (Lua):
    tbl = {}
    В Lua пополнение таблицы данными осуществляется, в основном, двумя способами
    a) по ключу:
    Код (Lua):
    tbl.ind  = ...
    tbl[ind] = ...
     
    Различие двух строк выше в том, что
    - первая создает ключ, который будет называться 'ind',
    - вторая (1) извлекает значение из переменной c названием ind и (2) присваивает его ключу , а если переменной ind не существует - выдает ошибку.

    Код (Lua):

    -- Получится для первой строки:
    tbl.ind = "data1"
    -- результат:
    tbl = {
       ind = "data1"
    }

    -- Для второй:
    ind = 'first'
    tbl[ind] = 'data2'
    -- Результат:
    tbl = {
       first = "data2"
    }
    б) индексированием:
    Код (Lua):
    table.insert(tbl, 'data1')
    -- на выходе этой функции будет таблица tbl такого вида:

    tbl = {
       'data1'
    }
    -- повтор:
    table.insert(tbl, 'data2')
    -- даст
    tbl = {
       'data1',
       'data2'
    }
    Вернемся к задаче о стандартном модуле для датчика DS18b20. В callback у него функция, которая:
    а) выполняется для каждого датчика по-отдельности
    б) получает в качестве аргументов:
    • ind - номер датчика по-порядку
    • rom - его адрес
    • res - разрешение, с каким он измеряет температуру
    • temp - температуру в плавающей точкой
    • tdec - десятичную часть температуры
    • par - паразитное питание датчика или нет
    Значит, следует выбрать данные, которые мы занесем в таблицу и то, как мы ее хотим видеть.
    Предлагаю сделать таблицу, где ключом будет адрес датчика, а полем - его значение.
    Это мой опыт: так лучше всего, когда вылетает из строя датчик. Остальные продолжают (в программе) работать и выдавать верные значения. Привязка же к порядковому номеру повлечет за собой перекос в работе датчиков, которые по номеру будут следующими за поломанным. Итак:

    Код (Lua):

    do
       -- Таблица для приема данных
       tbl = {}
       local pin = 4
       ds18b20.setting({}, 9)
       ds18b20.setup(pin)
        -- Функция для наполнения таблиц
       function maketable(ind,rom,res,temp,tdec,par)
         -- повторим форматирование адреса датчика, но начнем адрес с буквы 't' и уберем двоеточия
         local key = 't'.. string.format("%02X%02X%02X%02X%02X%02X%02X%02X",string.match(rom,"(%d+):(%d+):(%d+):(%d+):(%d+):(%d+):(%d+):(%d+)"))
         -- вставляем в таблицу данные
         tbl[key] = temp
       end
       -- Передаем сылку на нашу функцию в модуль DS18b20
       ds18b20.read(maketable,{},0x28))
        -- Распечатаем таблицу
        table.foreach(tbl, print)
    end
    И здесь у меня возник косяк. Сам же писал, что функция "ds18b20.read(maketable)" - асинхронная. Это значит, что после ее вызова код, следующий за ней, будет исполняться безостановочно. Следовательно, фунция "table.foreach(tbl, print)" будет вызвана еще до того, как таблица "tbl" наполнится данными.

    Надо заметить, что модуль от NodeMcu для датчика DS18b20 хотя и не косячит, но сделан непродуманно.
    Для одного датчика все будет работать правильно, если в callback (в нашем случае функция 'maketable') будут прописаны дальнейшие шаги. Вместе с тем, при многих датчиках мы не имеем информации о том, когда закончена обработка их всех.

    Выхода два.

    Первый. В функцию поступает информация о номере датчика "ind". Мы знаем сколько их у нас. Следовательно, продолжить работу можно, когда "ind" достигнет необходимой величины.

    Код (Lua):
    do
       -- Таблица для приема данных
       tbl = {}
       no = 2 -- Количество датчиков
       local pin = 4
       ds18b20.setting({}, 9)
       ds18b20.setup(pin)
        -- Функция для наполнения таблиц
       function maketable(ind,rom,res,temp,tdec,par)
         -- повторим форматирование адреса датчика, но начнем адрес с буквы 't' и уберем двоеточия
         local key = 't'.. string.format("%02X%02X%02X%02X%02X%02X%02X%02X",string.match(rom,"(%d+):(%d+):(%d+):(%d+):(%d+):(%d+):(%d+):(%d+)"))
         -- вставляем в таблицу данные
         tbl[key] = temp
         if no == int then
            -- Распечатаем таблицу
            table.foreach(tbl, print)
         end
       end
       -- Передаем сылку на нашу функцию в модуль DS18b20
       ds18b20.read(maketable,{},0x28))
    end
    Этот вариант неплох, но остановит работу программы, если хотя бы один датчик выйдет из строя.

    Второй
    вариант - применить таймер. Таймер выждет приблизительное время для наполнения таблицы данными и двинет программу дальше.

    Код (Lua):
    do
      -- Таблица для приема данных
      tbl = {}
      no = 2 -- Количество датчиков
      int = 750 -- время опрооса одного датчика
      local pin = 4
      ds18b20.setting({}, 9)
      ds18b20.setup(pin)
      -- Функция для наполнения таблиц
      function maketable(ind,rom,res,temp,tdec,par)
      -- повторим форматирование адреса датчика, но начнем адрес с буквы 't' и уберем двоеточия
      local key = 't'.. string.format("%02X%02X%02X%02X%02X%02X%02X%02X",string.match(rom,"(%d+):(%d+):(%d+):(%d+):(%d+):(%d+):(%d+):(%d+)"))
      -- вставляем в таблицу данные
      tbl[key] = temp
      end
      -- Передаем сылку на нашу функцию в модуль DS18b20
      ds18b20.read(maketable,{},0x28))
      tmr.create():alarm(no * int, 0, function()
         table.foreach(tbl, print)
      end)
    end
    И этот вариант тоже не слишком хорош - он подгружает память МК лишним таймером, без которого можно было бы обойтись при разумном написании модуля DS18b20.

    Дополнительно. В функции maketable нам не нужны ряд переменных. Чтобы не забивать память, можно сделать так: для тех что стоят до нужных нам - применить оператор '_' нижнее подчеркивание, а после нужных - вообще не упоминать

    Итого:
    Код (Lua):
    -- строку
    function maketable(ind,rom,res,temp,tdec,par)
    -- заменить на:
    function maketable(_,rom,_,temp)
    Результат - как выглядит таблица:
    Код (Lua):
    tbl = {
        t28FF8ACF63150191 = 26.5,
        t28FF3A3216150354 = 26.25
    }
     
    Последнее редактирование: 27 май 2018
    SmileOfFortune нравится это.
  9. ИгорьК

    ИгорьК Гуру

    Немного о таблицах - продолжение.

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

    Для таких случаев полезнее будет таблица вида:
    Код (Lua):
    tbl = {
       {t28FF8ACF63150191, 26.5},
       {t28FF3A3216150354, 26.25}
    }
    В чем профит?
    Та функция, что отправляет данные, будет забирать их путем уничтожения и проверять, не осталось ли еще. Есть данные - отправляем, нет - молчим. До написания такой функции мы еще дойдем, а вот ту, что пихает - напишем сейчас. Вот так:

    Код (Lua):
    do
       tbl = {}
       local pin = 4
       ds18b20.setting({}, 9)
       ds18b20.setup(pin)

       function maketable(_,rom,_,temp)
         -- повторим форматирование адреса датчика
         local key = 't' .. string.format("%02X%02X%02X%02X%02X%02X%02X%02X",string.match(rom,"(%d+):(%d+):(%d+):(%d+):(%d+):(%d+):(%d+):(%d+)"))
         -- вставляем в таблицу данные, изменив одну строку
         table.insert(tbl, {key, temp})
       end
       -- Передаем сылку на нашу функцию в модуль DS18b20
       ds18b20.read(maketable,{},0x28))

    end
     
    Последнее редактирование: 27 май 2018
    SmileOfFortune нравится это.
  10. Пытался я использовать Вашу библиотеку и другие... но безуспешно... похоже поменялись какие то параметры у модулей входящих в NodMcu. А новый Ваш код сейчас попробую.
     
  11. ИгорьК

    ИгорьК Гуру

    Скорее, Вы еще не до конца понимаете суть. Интерперетатор пишет об ошибках и надо внимательно смотреть что.
     
    SmileOfFortune нравится это.
  12. do
    -- Таблица для приема данных
    tbl = {}
    local pin = 4
    ds18b20.setting({}, 9)
    ds18b20.setup(pin)
    -- Функция для наполнения таблиц
    function maketable(ind,rom,res,temp,tdec,par)
    -- повторим форматирование адреса датчика, но начнем адрес с буквы 't' и уберем двоеточия
    local key = 't'.. string.format("%02X%02X%02X%02X%02X%02X%02X%02X",string.match(rom,"(%d+):(%d+):(%d+):(%d+):(%d+):(%d+):(%d+):(%d+)"))
    -- вставляем в таблицу данные
    tbl[key] = temp
    end
    -- Передаем сылку на нашу функцию в модуль DS18b20
    ds18b20.read(maketable)
    -- Распечатаем таблицу
    table.foreach(tbl, print)
    end
    script6.lua:14: wrong arg range
    stack traceback:
    [C]: in function 'read'
    script6.lua:14: in main chunk
    [C]: in function 'dofile'
    stdin:1: in main chunk
    Немного скудная информация дается... или я не понимаю ее... немного привык к другим ответам об ошибках и описания их...
    Что касается этой ошибки, то это как я понимаю не верная размерность аргумента...
     
  13. ds18b20.read(maketable,{},0x28)
    сделал вызов в таком виде. Ошибок нет. Но и вывода показаний нет. если вручную скармливать по линии
    ds18b20.read(maketable,{},0x28) а потом table.foreach(tbl, print) то выводит
    t28FF3A3216150354 29.125
    t28FF8ACF63150191 29.5
     
  14. ИгорьК

    ИгорьК Гуру

    Так не годится.
    1. Уберите все комментарии к коду перед запуском.
    2. Укажите о какой строке речь.
     
    SmileOfFortune нравится это.
  15. ИгорьК

    ИгорьК Гуру

    Да, это правильный вызов, я недоглядел.
    Поправлю чуть позже код.
     
    SmileOfFortune нравится это.
  16. do
    tbl = {}
    local pin = 4
    ds18b20.setting({}, 9)
    ds18b20.setup(pin)
    function maketable(_,rom,_,temp)
    local key = 't' .. string.format("%02X%02X%02X%02X%02X%02X%02X%02X",string.match(rom,"(%d+):(%d+):(%d+):(%d+):(%d+):(%d+):(%d+):(%d+)"))
    table.insert(tbl, {key, temp})
    end
    ds18b20.read(maketable)

    end
    dofile("scrip6t3.lua")
    scrip6t3.lua:10: wrong arg range
    stack traceback:
    [C]: in function 'read'
    scrip6t3.lua:10: in main chunk
    [C]: in function 'dofile'
    stdin:1: in main chunk

     
  17. ИгорьК

    ИгорьК Гуру

    Это мой недогляд - неправильный выов, вы сами нашли ошибку - потеряна таблица.
     
    SmileOfFortune нравится это.
  18. Но при этом другая проблема. Таблица автоматом не выводится...
    do
    tbl = {}
    local pin = 4
    ds18b20.setting({}, 9)
    ds18b20.setup(pin)
    function maketable(_,rom,_,temp)
    local key = 't' .. string.format("%02X%02X%02X%02X%02X%02X%02X%02X",string.match(rom,"(%d+):(%d+):(%d+):(%d+):(%d+):(%d+):(%d+):(%d+)"))
    table.insert(tbl, {key, temp})
    end
    ds18b20.read(maketable,{},0x28)
    table.foreach(tbl, print)
    end
    >dofile("scrip6t3.lua")
    >
     
  19. ИгорьК

    ИгорьК Гуру

    По поводу библиотеки от NodeMcu. Она не то чтобы кривая, она просто недодумана и пользоваться ей не удобно, ИМХО.
    Попробуйте мою.
    ! В прошивке должен быть модуль One wire.
     
  20. ИгорьК

    ИгорьК Гуру

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