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

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

  1. Maksgen

    Maksgen Нерд

    Сборка прошивки для ESP8266 через DOCKER
    Решил попробовать собрать прошивку самостоятельно как указано в документации на NodeMCU https://nodemcu.readthedocs.io/en/release/modules/sntp/ Проект NodeMCU по умолчанию включает готовую цепочку инструментов для Linux / x86-64. Поэтому необходимо установить Linux на компьютер (с Raspberry Pi не получиться, так как там 32 разрядный Linux). Поэтому установил VirtualBox и установил UBUNTU 20.04, Сделал все как по инструкции как в документации, изменил необходимые данные на модули, запустил make и .... получил ошибку в файле make, т.е. сборка не удалась. Может какие то проблемы с версиями программ, с версиями Linux. на знаю.
    Там же в документации предложено, чтобы не настраивать среду Linux, для сборки использовать Docker NodeMCU build. Но она предполагает наличие компьютера с Windows 10. У меня Windows 8.1, а для нее надо устанавливать docker toolbox. Попробовал, однако при установке изменяется программа VirtualBox на старую версию (хотя и снял галочку установить VirtualBox), и не нашел дополнений к гостевой ОС, соответственно не подключается мышь (нет драйверов), видимо надо скачивать отдельно.
    Вышел из положения следующим образом!
    Установил последнюю версию VirtualBox на компьютер с Windows 8.1, установил в виртуальную машину UBUNTU 20.04 (делается все очень просто, надо скачать iso файл с UBUNTU с официального сайта, иметь UltraISO, для создания виртуального диска и далее по инструкции, например https://ru.wikihow.com/установить-Ubuntu-в-VirtualBox.) Далее надо смонтировать через UltraISO виртуальный диск с VBoxGuestAdditions.iso , который находится в папке C:/Program Files/Oracle/VirtualBox и запустить Дополнения к гостевой ОС. Установить общий буфер обмена.
    Далее через Ubuntu устанавливаем DOCKER по инструкции https://www.digitalocean.com/community/tutorials/how-to-install-and-use-docker-on-ubuntu-20-04-ru. ОБЯЗАТЕЛЬНО СДЕЛАЙТЕ ШАГ №2 !!!

    Далее в соответствии с документацией на https://hub.docker.com/r/marcelstoer/nodemcu-build/ запускаем команду
    docker pull marcelstoer/nodemcu-build

    Для этого в VirtualBox с установленной машиной UBUNTU надо нажать ctrl+alt+t И перейти в терминал. Если Вы установили в VeryualBox общий буфур обмена, то команды можно копировать и вставлять.

    Если появляется ошибка, что отказано в связи с host docker, то вы не сделали шаг №2 инструкции и не прописали пользователя в группу docker!

    Далее надо клонировать с GitHab драйвера и модули для NodeMCU
    Запускаем команду

    git clone --recurse-submodules https://github.com/nodemcu/nodemcu-firmware.git

    В папке /home/<user./ появиться папка со скаченными файлами. Ее также можно найти в VirtualBox в папке Фалы. Откройте ее, перейдите в папку nodemcu-firmware далее в папку app/include/ . Находим файл user_modules.h и в соответствии с Вашими желаниями собираем (раскоментируем) необходимые модули. Все описано в документации https://nodemcu.readthedocs.io/en/release/build/ Так же корректируем файл user_config.h и если необходим дисплей, то файлы u8g2_displays.h и u8g2_fonts.h

    Далее надо в терминале набрать команду!!!!

    cd /home/<user>/nodemcu-firmware

    <user> это Ваше имя по которому вы вошли в UBUNTU
    Это мы переходим в каталог со скаченными файлами

    После этого можно запускать сборку командой

    docker run --rm -ti -v `pwd`:/opt/nodemcu-firmware marcelstoer/nodemcu-build build

    После сборки, файлы bin с программой прошивки для NodeMCU появятся в папке bin (внутри папки nodemcu-firmware)
    Там появятся 4 файла:
    0x00000.bin - для прошивки по воздуху
    nodemcu_${BUILD_TYPE}_${IMAGE_NAME}.bin -прошивка, например через ESP8266Flasher
    файл .map
    и файл 0x10000.bin - файл SPIFFS.

    Основной файл прошивки будет float. так как по умолчанию так установлено, если нужна целочисленная прошивка надо внести изменения в файл user_config.h.

    Чтобы передать файл из виртуальной машины в Windows надо настроить общую папку для VirtualBox. Создадим папку например Docker по адресу пользователь/user/. Входим в VirtualBox и эту папку настраиваем как общую. Входим в меню Файлы в UBUNTU, находим каталог Домашняя папка, в ней папку nodemcu-firmware, заходим, открываем папку bin. Там находятся собранные 4 файла. Надо скопировать в буфер файл с программой.bin, перейти опять в паку Файлы и в самом низу будет отображаться общая папка sf_Docker. Входим в нее и из буфера записываем файл программы, Потом из под Windows можно зайти в папку Docker и забрать файл.

    Довольно долго устанавливать все программы, но сама сборка, после установки всех программ, занимает примерно около 5 минут.
     
    Последнее редактирование: 30 ноя 2020
    serg3295, swc и ИгорьК нравится это.
  2. ИгорьК

    ИгорьК Гуру

    О как. Наших все больше...


    Так или иначе, со временем, приходишь к неWindows.
    У меня докер на Debian и там все собирается с меньшим количеством телодвижений. Прошивки забираются через WinCSP по ssh.

    Правда один Debian - виртуальная машина на qnap, другой - виртуальная машина на TrueNas.
     
    serg3295 нравится это.
  3. swc

    swc Гик

    Весной заморачивался с получением исходников с целью сделать компилятор и самому делать прошивку и LFS. Установил Ubuntu рядом с Windows, Docker, все получилось.
    Компилировал в Windows через MinGW.
    Сейчас все проще: Исходники и компилятор лежит здесь:
    https://github.com/nodemcu/nodemcu-firmware/releases
    Компилировать отсюда еще не пробовал (нет времени) но, думаю особых проблем быть не должно.
    То есть, разработчики облегчают жизнь тем, кто под Windows.
     
    serg3295 и ИгорьК нравится это.
  4. serg3295

    serg3295 Гик

    Это всё хорошо, когда у вас архитектура x86. Тут и готовые тулчейны собраны под архитектуру x86. И описания тебе, и докеры.

    Однако, через некоторое время мне надоело запускать виртуалку OracleVM для генерации прошивки, а тем более устанавливать её на других машинах. Докер я ставить не хотел на все свои Windows, а на моём старом QNAPe с 1Гб памяти он не шёл. Поэтому встала задача по сборке прошивок nodemcu ESP8266 & ESP32 на архитектуре, отличной от x86.
    Сборки проводились на машинах raspberry pi3 с архитектурой armv7l и старом asus eeePC с архитектурой linux-i686.

    Как это делается:

    Сначала необходимо сгенерировать toolchain для целевой архитектуры.
    Устанавливаем пакеты
    Код (C++):
    sudo apt-get install git wget gawk gperf grep gettext libncurses-dev python python-dev automake bison flex texinfo help2man libtool libtool-bin make
     
    создаём каталог ~/nodemcu и переходим в него
    забираем репозиторий сборки toolchains

    git clone https://github.com/jmattsson/esp-toolchains/

    переходим в esp-toolchains/
    корректируем Makefile под старый компилятор. С 2019r1 тулчейн соберётся, а прошивка esp32 нет. По крайней мере, у меня так было.
    Код (C++):

    build/esp32/bootstrap:
    #   $Qcd build && git clone -b esp32-2019r1_ctng-1.23.x https://github.com/espressif/crosstool-NG.git esp32
       $Qcd build && git clone -b xtensa-1.22.x https://github.com/espressif/crosstool-NG.git esp32
       @touch $@

    #build/esp32/patched: build/esp32/bootstrap
    build/esp32/Makefile: build/esp32/bootstrap
    #   $Qcd "$(dir $@)" && patch -p0 < ../../esp32-configure.patch
    #   @touch $@

    #build/esp32/Makefile: build/esp32/patched
       $Qcd "$(dir $@)" && ./bootstrap && ./configure --prefix="`pwd`"
    Сборка toolchain'а для ESP8266
    сборка на малине длится около 2-х часов. Для старта запускаем
    make esp8266

    Внимание! В имени получившихся архива и каталога автоматически подставляется архитектура и дата сборки в формате ГодМесяцДень.номер То есть, у вас будет своя дата ВАША_ДАТА.порядковый номер сборки (обычно 0, если вы, конечно, не собрали несколько тулчейнов за один день).

    На выходе, в случае успешного завершения, получаем архив в папке
    ~/nodemcu/esp-toolchains/build/toolchain-esp8266-linux-armv7l-ВАША_ДАТА.0.tar.xz

    На этом шаге можно перейти к сборке прошивки esp8266 а потом вернуться к тулчейну esp32

    Сборка toolchain'а для ESP32. Запускаем
    make esp32

    В результате получим архив
    ~/nodemcu/esp-toolchains/build/toolchain-esp32-linux-armv7l-ВАША_ДАТА.0.tar.xz

    Сборка прошивок
    Устанавливаем пакеты:
    Код (C++):
    sudo apt-get install -y gperf python-pip python-dev flex bison build-essential libssl-dev libffi-dev libncurses5-dev libncursesw5-dev libreadline-dev
    python -m pip install pyserial
    Сборка прошивки для esp8266
    Скачиваем архив tar.gz https://github.com/nodemcu/nodemcu-firmware/releases с нужным релизом и распаковываем его в ~/nodemcu/nodemcu-firmware ну,например.
    примечание:
    в релизе 3.0-release_20201107 к исходникам надо руками подгрузить субмодуль c99-snprintf

    cd ~/nodemcu/nodemcu-firmware/app/libc
    git clone https://github.com/weiss/c99-snprintf

    Если нужно для удобства последующей прошивки, то можно (установив пакет srecord) собрать получившиеся в каталоге /bin файлы в один файл командой srec_cat
    создаём в каталоге ~/nodemcu/nodemcu-firmware файл build.sh, пишем туда:
    Код (C++):
    make TOOLCHAIN_ROOT=~/nodemcu/esp-toolchains/esp8266-linux-armv7l-ВАША_ДАТА.0
    DATE=$(date +%Y%m%d)
    srec_cat -output ./bin/nodemcu$DATE.bin -binary ./bin/0x00000.bin -binary -fill 0xff 0x00000 0x10000 ./bin/0x10000.bin -binary -offset 0x10000
    и делаем файл build.sh исполняемым

    настраиваем путь к компилятору, написав в файл ~/.bashrc вот это:
    Код (C++):

    # it's for esp8266
    export PATH=$PATH:"/home/ВАШЕ_ИМЯ/nodemcu/esp-toolchains/esp8266-linux-armv7l-ВАША_ДАТА.0/bin"
     
    применяем путь
    source ~/.bashrc

    теперь правим .h под себя и запускаем сборку прошивки через build.sh

    Сборка прошивки для esp32
    идём в каталог ~/nodemcu и оттуда выполняем команду
    Код (C++):
    git clone --branch dev-esp32 --recurse-submodules https://github.com/nodemcu/nodemcu-firmware.git nodemcu-firmware-esp32
    Получив репозиторий, создаём в ~/nodemcu/nodemcu-firmware-esp32 каталог cache и копируем в него архив tar.xz
    ~/nodemcu/nodemcu-firmware-esp32/cache/toolchain-esp32-linux-armv7l-ВАША_ДАТА.0.tar.xz

    Немножко корректируем Makefile, а именно, пишем нашу дату сборки в переменную TOOLCHAIN_VERSION
    Код (C++):

    TOOLCHAIN_RELEASES_BASEURL:=https://github.com/jmattsson/esp-toolchains/releases/
    TOOLCHAIN_VERSION:=ВАША_ДАТА.0
    PLATFORM:=linux-$(shell uname --machine)
    И закомментируем wget, так как мы уже положили toolchain в cache
    Код (C++):
    $(ESP32_TOOLCHAIN_DL):
      @mkdir -p $(THIS_DIR)/cache
    #  wget --tries=10 --timeout=15 --waitretry=30 и что-то там ещё
     
    отлогинтесь и снова войдите по ssh, чтобы прописался путь в ~/.local/bin
    выполните
    Код (C++):
    /usr/bin/python -m pip install --user -r /home/ВАШЕ_ИМЯ/nodemcu/nodemcu-firmware-esp32/sdk/esp32-esp-idf/requirements.txt
    собираем прошивку
    make

    Что имеем в итоге.
    1. постоянно включенная машина-сборщик в моей VPN сети позволяет сгенерить прошивку просто подключившись Bitvise SSH. Что по времени быстрее, чем запуск VM. Да и машина одна, поэтому все коллекции прошивок в одном месте. Это удобно.
    2. в случае raspberry, я поставил в VS Code дополнение Remote-SSH, что позволило заходить на малину и корректировать *.h прямо из VSCode. А также забирать бинарники с малины не через SCP. То есть всё делал из одной среды. Однако, малина перешла на другую работу :), а на архитектуре linux-i686 это дополнение не работает. Так что всё по старинке. Через терминал.
     
    ИгорьК и swc нравится это.
  5. serg3295

    serg3295 Гик

    В процессе борьбы с несколькими устройствами ESP-8266 с нестабильным WiFi каналом обнаружил неприятную особенность стека MQTT текущей прошивки.
    А именно, при пропадании канала WiFi, если изредка делать m: publish(), то функции "offline" и "connfail" сработают только после восстановления канала. То есть, флаг разрешения публикации в канал mqtt не сбросится. И устройство будет думать, что у него всё хорошо.
    Для решения проблемы, конечно, можно в проверке wifi заодно сбрасывать флаг mqtt, но это мне не понравилось. Вариант два - сделал в приложенных файлах. Просто ещё флаг в "puback".
    Вопросы.
    - Я где-то ошибся в коде, или это повторяемая особенность?
    - можно ли предложить более элегантное решение проблемы (ну, если она, конечно, есть)?
    Код (C++):
    -- MQTT config
    mqttClientID = "node104"
    mqttON = false --соединение установлено
    mqttPuback = false --нет успешных публикаций

    -- ************ СТАРТ ******
    print("start main")
    -- Запустили mqtt
    tmr.create():alarm(5000, tmr.ALARM_AUTO, function(t)
        iswifi = wifi.sta.status()
        if  iswifi == wifi.STA_GOTIP then
            print("start mqtt")
            -- Устанавливаем связь с брокером
            if file.exists("mqttset.lua") then dofile("mqttset.lua") end
            t:stop(); t:unregister(); t = nil
        end
    end)

    -- Начинаем публиковать
    tmr.create():alarm(4000,  tmr.ALARM_AUTO, function()
        if mqttON then
            local he = ""..node.heap()
            print(he)
            -- m:publish("test/", he, 0, 0) --если так, "offline" сработает только после восстановления канала
        -- поэтому проверяем были ли успешные публикации от "puback"
            if mqttPuback then --вариант 2
                mqttPuback = false
                m:publish("test/", he, 0, 0)
            end
        end
    end)
     
    Код (C++):
    -- MQTT config
    local mqttKeepalive = 10
    local mqttBroker = "192.168.1.31"
    local mqttPort = 1883
    local mqttUser = "u"
    local mqttPass = "p"

    local mqttConnect, mqttNew, mqttErr

    function mqttErr(client,reason)
        client, reason, m = nil, nil, nil
        tmr.create():alarm(15000, tmr.ALARM_AUTO, function(t)
            net.dns.resolve('domoticz.lan', function(sk, ip)
                print(ip)
                if ip == mqttBroker then
                    t:stop(); t:unregister(); t = nil
                    ip = nil
                    mqttConnect(mqttNew())
                end
            end)
        end)
    end

    function mqttNew()
        ---@type mqtt
        m = mqtt.Client(mqttClientID, mqttKeepalive, mqttUser, mqttPass, 1)
        m:lwt("stat/"..mqttClientID, "offline", 0, 0)

        m:on("offline", function(client)
            mqttON = false
            client:close()
            print("mqtt offline")
            mqttErr()
        end)
        m:on("connfail", function(client, connFailCode)
            print("mqttConnectError: ", MQTTconnFailReasonCodes[connFailCode])
            print("client: ", client)
            mqttON = false
        end)
        m:on("puback", function()
            print("puback")
            mqttPuback = true
        end)
        m:on("message", function(client, topic, message)
            print(topic)
            print(message)
        end)

        return m
    end

    function mqttConnect(m)
        print("object m = ", m)
        m:connect(mqttBroker, mqttPort, false,
            ---@class client : mqtt
            function(client)
                mqttON = true
                client:publish("stat/"..mqttClientID, "online",0, 0)
                print("mqtt connected")
                client:subscribe(mqttClientID.."/cmnd", 0)
                print("subscribed -> /cmnd")
            end)
    end

    mqttErr()
     
     
    swc и ИгорьК нравится это.
  6. alp69

    alp69 Форумчанин

    Было у меня такое на стандартной прошивке от nodemcu. События отрабатывались не своевременно. Невзирая на наличие или отсутствие канала, перед m: publish() принудительно закрывать соединение и заново его устанавливать.
    Или играться с QoS.
     
    swc, serg3295 и ИгорьК нравится это.
  7. ИгорьК

    ИгорьК Гуру

    Лучше делать где поменьше памяти надо :)

    Затратно.

    У меня свистопляска была, когда работал с публичным брокером. Все останавливалось без пояснения причин.
    На отправку ставил таймер. В callback публикации - останов таймера, иначе таймер через секунду объявляет ошибку коннекта и вызов функции error. Очень надежно работает.

    Но с домашними брокерами проблем нет в принципе.
     
    swc и serg3295 нравится это.
  8. serg3295

    serg3295 Гик

    Не стал ничего изобретать, просто решил проблему "в лоб". Вероятность того что канал отвалится сразу перед publish существенно меньше. Да и callback в publish перерегистрируется на последний используемый в коде, так что идея с "puback" ограничивает применение publish callback в теле программы.
    Код (C++):
    local function publWithCheck(par)
        net.dns.resolve("domoticz.lan", function(sk, ip)
            if ip == "192.168.1.31" and mqttON then
                m:publish("stat/"..mqttClientID, par, 0, 0)
            end
        end)
    end
    -- Начинаем публиковать
    tmr.create():alarm(4000,  tmr.ALARM_AUTO, function()
            local he = ""..node.heap()
            publWithCheck(he)
    end)
     
    swc и ИгорьК нравится это.
  9. swc

    swc Гик

    Для домашней сети решил избавиться от Wi-Fi - слишком много фона. Передатчики постоянно включены, а это для здоровья не есть хорошо. Делаю сеть CSMA/CD на UART 2.4GHz, что позволит отказаться от локального MQTT сервера. Для связи с облачным MQTT сервером оставлю только один узел с Wi-Fi.
     
  10. SergeiL

    SergeiL Оракул Модератор

    А отказ от локального сервера в пользу публичного не снизит надежность при потере канала в интернет или падения публичного?
     
  11. ИгорьК

    ИгорьК Гуру

    С публичным бесплатным брокером будут зависать железки, если не принимать дополнительные меры. С платным - не знаю.

    ... однако "кому суждено утонуть, тот не угорит". Избегаешь одного, получишь другое. Проверено.
     
    Последнее редактирование: 15 дек 2020
  12. swc

    swc Гик

    Отказ от локального не в пользу публичного. Публичный - если есть необходимость удаленного управления. В противном случае он также не нужен, как и локальный. Опционально.
    Mqtt-2-crop.jpg
     
  13. ИгорьК

    ИгорьК Гуру

    Чет не въехал. Совсем отказ от брокера? COAP?
     
  14. swc

    swc Гик

    Совсем, если в этом нет острой необходимости. Каждый узел сети может обратиться к любому другому узлу и передать/получить команду или данные. Каждый узел может взаимодействовать с оператором. Поэтому с пульта сеть можно администрировать из любого места в зоне покрытия сети.
     
    ИгорьК нравится это.
  15. ИгорьК

    ИгорьК Гуру

    Все равно не понял идею. Отказаться всего от одного устройства wifi?

    А чем это отличается от wifi принципиально для здоровья?
     
  16. swc

    swc Гик

    Как минимум, одно устройство Wi-Fi остается. Для связи с Интернет, облачным MQTT, компьютером, смартфоном и с пультом управления.
    Если у меня в сети более десятка Wi-Fi устройств в радиусе от 5 до 70 м, то это не есть полезно для здоровья. Передатчики Wi-Fi постоянно включены и мониторят связь.
    Трансиверы UART 2.4GHz постоянно работают на прием и включаются на передачу в момент посылки данных на десяток миллисекунд.
     
    ИгорьК нравится это.
  17. ART_HA

    ART_HA Нерд

    Если у кого-то наблюдается проблема в виде отсутствия связи NodeMCU в ESPlorer после reset, установите последнюю версию ESPlorer: https://github.com/4refr0nt/ESPlorer/releases
     
    ИгорьК нравится это.
  18. ИгорьК

    ИгорьК Гуру

    Все таки Lua? Не Ардуино????
     
  19. ART_HA

    ART_HA Нерд

    Пока едет ESP32 имеет смысл поковыряться в LUA на предмет его использования уже в ESP32.
     
  20. serg3295

    serg3295 Гик

    Понемногу разобрался с аннотированием функций в расширении sumneko/lua-language-server для VS Code. Возможности данного расширения в настоящее время даже превысили функционал расширения Emmy Lua. За счёт автодополнения стало очень удобно набирать код, в том числе и для nodeMCU, если были предварительно описаны функции.
    Я начал аннотировать встроенные функции nodeMCU для удобства в работе. Пока процесс идёт, ещё не всё введено, наверное, есть ошибки. Однако, основные функции присутствуют. Рабочие версии лежат на git.
     
    swc и ИгорьК нравится это.