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

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

  1. В коде нигде не устанавливается точность. Разрешение первого датчика 0,5 а у второго 0,1. неважно, вместе они работают или порознь... и в каком гнезде...
     
  2. ИгорьК

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

    В библиотеке от NodeMCU разрешение устанавливается:
    Код (C++):
    ds18b20.setting({"28:FF:FF:FF:FF:FF:FF:FF"}, 9)
    В моей такой функции не предусмотрено.
     
  3. Я про это и говорю. Если использовать стандартную функцию установки точности, то она работает, но опять с одним только датчиком. На второй не распространяется установка.
    У Вас нет установки точности, но результат тот же... разрешение у датчиков разное. Складывается впечатление, что сам датчик имеет "встроенное разрешение" чего по сути не должно быть.
     
  4. ИгорьК

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

    Разрешение, установленное однажды, сохраняется. Если вы установили его библиотекой от NodeMcu - оно и осталось. Изменяйте его, подключая датчики по-отдельности.
     
    Последнее редактирование: 29 май 2018
    SmileOfFortune нравится это.
  5. Пробовал, не помогает, точнее точность не меняется ни у одного из двух. Как было у одного 9 а у другого 12, так и осталось...
     
  6. ИгорьК

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

    Не могу прокомментировать. Либо ошибки в библиотеке, либо вы ошибаетесь в адресах.
    Если это важно - поменяйте разрешение через ардуино, если она есть.
     
    SmileOfFortune нравится это.
  7. ИгорьК

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

    Еще вариант (безумный) - играть с буквенными частями адреса: проверять и строчные и прописные буквы.

    Где-то я встречался с таким явлением.

    Попробуйте дать команду на установку разрешения с заранее несуществующим адресом. Если библиотека не выдаст ошибку - возможно дело в формате его указания. Но каким он должен быть - только методом инженерного тыка.
     
  8. ИгорьК

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

    Глядя на код от NodeMcu, могу предположить что адрес еще может выглядеть не как шестнадцатеричные, а как десятичные числа разделенные двоеточием.
     
  9. fixedip

    fixedip Гик

    Добрый вечер.
    А можно рассказать по UART в Lua?
     
  10. ИгорьК

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

    Пока в планах нет, поскольку uart он везде одинаков. Посмотрите здесь, например: http://forum.amperka.ru/threads/arduino-esp8266-raspberry-pi-2-openhab-Умный-дом-азы-управления.5043/page-20#post-65454

    Что надо сказать - в прошивках версии 2.х.х UART1 работает только на передачу, а в версиях 1.х.х - нормально. Это надо учитывать.

    Вообще, смотрите тему про ОН - там есть несколько устройств Lua с UART: http://forum.amperka.ru/threads/arduino-esp8266-raspberry-pi-2-openhab-Умный-дом-азы-управления.5043/
     
  11. ИгорьК

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

    Скелет программы IoT ч.2.

    Рассмотрим еще несколько файлов/действий, которые требуются любому устройству домашней автоматизации.
    Чем бы ни занималось устройство, оно:
    1. получает и обрабатывает команды от брокера;
    2. отправляет информацию о своем состоянии;
    3. сохраняет в память некоторые параметры, которые важны в случае перезагрузки или отключения питания.
    Займемся указанными вопросами.

    4. pubnow.lua

    Работа организована таким образом, что любая часть программы, которая хочет отправить информацию на брокер, должна поместить данные в глобальную таблицу "topub" и, если не поднят флаг "dat.publ", выполнить "dofile('pubnow.lua')".

    Флаг "dat.publ" поднимает и сбрасывает сам скрипт. Скрипт по одной изымает строки из таблицы для публикации, публикует данные на брокер и рекурсивно в callback вызывает публикацию новой строки, пока они все не будут изъяты из таблицы.

    Так как публикация дело долгое и асинхронное, не возбраняется в ее ходе подкинуть в таблицу еще значения - они будут также отправлены. А вот вызывать "dofile('pubnow.lua')" во время его работы нельзя, предотвращение тому - флаг "dat.publ" .

    Итак:
    Код (Lua):
    do
    dat.publ = true -- Флаг публикации
    --[[
    -- Это для преобразования таблиц с ключом в индексируемые
    -- потребуется позже
    for k,v in pairs(tohome) do
        table.insert(topub, {k, v})
    end
    --]]

    -- Всегда публикуем 'heap', за ним надо наблюдать
    table.insert(topub, {'heap', node.heap()})
    local function punow()
        -- Если в таблице для публикации что-то есть и она возможна
        if #topub ~= 0 and wifi.sta.getip() and dat.broker then
            -- Изымаем элемент из таблицы
            local tp = table.remove(topub)
            -- Элемент с индексом 2 (сообщение топика) может отсутствовать
            tp[2] = tp[2] or ""
            -- Если сообщения нет, то поднимаем флаг "Retained"
            -- чтобы удалить на брокере принятое от него сообщение
            tp[3] = tp[2] == "" and "1" or "0"
            -- Публикуем и вызываем себя рекурсивно:
            m:publish(myClient.."/"..tp[1], tp[2], 0, tp[3], punow)
        else
            tp = nil
            dat.publ = nil
            punow = nil
            print('Published!')
            return
        end
    end
    punow()
    end

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

    5. analize.lua
    В прошлой заметке этот файл просто печатал данные, сегодня мы озадачим его двумя вещами: пусть включает/выключает освещение и устанавливает целевую температуру для поддержания.

    Замечу, что файл "analize.lua" универсальным по содержанию быть не может, но само его наличие и приемы работы с ним - универсальны.
    Логика его работы приблизительно такая же как у "pubnow.lua" - изымаем из таблицы данные для анализа, пока они не закончатся.

    Код (Lua):
    dat.analiz = true -- Анализ данных с брокера начался
    if #killtop ~= 0 then -- В таблице для анализа есть данные
        -- Выдергиваем запись из таблицы
        local com = table.remove(killtop)
        local top = com[1]
        local dt = com[2]
        -- Разбираем пару топик-дата
        if top and dt then
            -- Здесь тема освещения
            if top == "light" then
                if dt == "ON" then
                    dat.light = "ON"
                    gpio.write(pinlight, gpio.HIGH)
                    print("Light is ON")
                end
                if dt == "OFF" then
                    dat.light = "OFF"
                    gpio.write(pinlight, gpio.LOW)
                    print("Light is OFF")
                end
            -- Тема установки целевой температуры
            elseif top == "target" then
                -- Формируем цифру, а если мусор - 75
                local target = tonumber(dt) or 75
                -- Дальше защищаемся от неправильной уставки
                if target == 75 then
                    print('Got Wrong Target!')
                else
                    if target < 15 then
                        dat.target = 15
                    elseif target > 27 then
                        dat.target = 27
                    else
                        dat.target = target
                    end
                end
                target = nil
                print('Set Target Temperature At '..dat.target)
            end
        end
        com, top, dt = nil, nil, nil
        -- Вызываем себя рекурсивно для проверки данных от брокера
        dofile('analize.lua')
    else
        -- Данные для анализа кончились - уничтожаем флаг
        dat.analiz = nil
    end
     
    Последнее редактирование: 16 июн 2018 в 12:45
  12. ИгорьК

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

    6. savedata.lua (плюс вспомогательный listtosave.lua)
    Этот файл может вызываться из тех мест программы, где изменились некоторые важные данные и это изменение надо защитить от перезагрузки или потери питания.
    Например, мы поливаем помидоры каждый день, а когда пойдет рост плодов - дадим команду на полив через день. Или поменяем целевую температуру нагревателя и т.д.

    Рабочие данные у нас всегда находятся в таблице "dat". Эта таблица устанавливается в скрипте "setglobals.lua", например так:
    Код (Lua):
    dat = {}
    dat.target = 22 -- Целевая температура
    dat.light = 'OFF' -- Освещение выключено
    dat.broker = false -- Связи с брокером нет
    Здесь же, после формирования таблицы параметров, можно поместить такой код:
    Код (Lua):
    -- Если файл 'setsaveddat.lua' есть - выполним его
    if file.exists('setsaveddat.lua') then
          dofile('setsaveddat.lua')
    end
    По ходу работы нашего устройства файл 'setsaveddat.lua' может появиться и мы займемся его появлением. Он, например, будет перезаписывать целевую температуру относительно установленной в "setglobals.lua".
    Перечень ключей таблицы "dat" для сохранения находится в файле "listtosave.lua":
    Код (Lua):
    return {
       -- {'light'},
        {'target'}
    }
    Сам файл, который делает сохранение, выглядит так:
    Код (Lua):
    do
        -- "lst" - таблица с перечнем ключей, которые будут
        -- сохранены из рабочей таблицы 'dat'
        local lst = dofile('listtosave.lua')
        -- создаем и открываем временный файл
        tmp = file.open("tmp.lua", "w")
        if tmp then
            local line
            -- Выбираем значения из перечня полей для сохранения
            for _, v in pairs(lst) do
                -- Формируем строку для сохранения, печатаем и сохраняем
                -- во временный файл
                line = "dat."..v[1].."="..dat[v[1]].."\n"
                print('write: '..line)
                tmp:write(line)
            end
        end
        tmp:close(); tmp = nil
        -- Удаляем старый файл и заменяем новым
        file.remove("setsaveddat.lua")
        file.rename("tmp.lua", "setsaveddat.lua")
        lst = nil
    end

    Итак, если, например, в файл "analize.lua" в часть, где идет управление целевой температурой добавить одну строку
    Код (Lua):
    ...
    print('Set Target Temperature At '..dat.target)
    -- добавим:
    dofile('savedata.lua')
    ...
    то после каждой команды от брокера новый "dat.target" будет сохраняться в файле "setsaveddat.lua", который будет создан без вашего участия и вызываться при старте.

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

    Уже в таком виде, будучи загруженными в модуль, мы можем дистанционно управлять одной ногой (можете добавить еще) еспшки.
    В комплекте и файл main.lua, который каждые 2 минуты гонит на брокер информацию о текущих параметрах устройства.

    Кроме того, в файле "pubnow.lua" QoS при публикации установлено в 2 и закомментирован костыль, который нужен лишь в том случае, если связь с брокером чрезвычайно плохая и от него не всегда доходят сообщения.

    Вот как это работает, и здесь, кстати, видно переподключение:
    upload_2018-6-15_20-56-14.png

    upload_2018-6-15_20-57-8.png

    Все работает. Осталось наполнить файл "main.lua" чем-нибудь полезным.
    А пока этим можно управлять со смартфона через MQTT Dash:
    SmartSelect_20180619-015834_MQTT Dash.jpg
     

    Вложения:

    • iot02.zip
      Размер файла:
      3,1 КБ
      Просмотров:
      8
    Последнее редактирование: 19 июн 2018 в 02:59
  13. swc

    swc Нерд

    Отличное пособие для начинающих! Lua - очень замечательный язык. А в совокупности с библиотекой NodeMCU - бомба.
    Добавлю еще одну полезную фичу. (Польза проявится в процессе освоения и работы с Lua).

    Код (Lua):

    -- файл: "init.lua". Кнопочка с GPIO на землю позволяет устранить головную боль
    -- вариантов опубликовано много, это мой.
    local GPIO = 2 -- у меня так, использую дисплей
    gpio.mode(GPIO, gpio.INPUT,gpio.pullup)
    if gpio.read(GPIO) == 1 then
         print("==== RUN ====")
         dofile "main.lua"
    else
        print("==== STOP ====")
    end
     
    Последнее редактирование: 16 июн 2018 в 16:47
    ИгорьК нравится это.