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

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

  1. Rost_admin

    Rost_admin Нуб

    То есть это код не подходит для NodeMCU V3 Lua т.к. она собрана на чипе ESP-12E. Я верно понимаю ?
     
  2. ИгорьК

    ИгорьК Гуру

    Есть ESP-8266 и есть ESP32. Это разные устройства с точки зрения железа.
    В пределах этих устройств как они сделаны разницы нет.
    ESP-12, ESP-201, ESP-1 - это все ESP-8266 в разных количествах ног и обвязки.
    Есть чип ESP-8285 - это (в целом) тоже ESP-8266.

    Итого, есть Lua для esp32 и для ESP-8266.
    Смотрите внимательнее, в топиках видно о чем идет речь. Последнее время - ESP32.
     
  3. Rost_admin

    Rost_admin Нуб

    Теперь понятно. Но вот вопрос. На старой прошивке у меня вот это код работал в init.lua

    Код (C++):
    print ( "Waiting ...")
    tmr.register (0, 5000, tmr.ALARM_SINGLE, function (t) tmr.unregister (0); print ( "Starting ..."); dofile ( "main.lua") end)
    tmr.start (0)
    На новой ошибка:
    [​IMG]

    Где почитать как правильно построит скелет проекта?

    То есть что бы программа была разбита на модули и вызов этих модулей осуществлялся из init.lua
     
  4. ИгорьК

    ИгорьК Гуру

    Вся тема этому посвящена. Удивлю: в ней есть заголовок.
     
  5. ИгорьК

    ИгорьК Гуру

    И про таймер здесь есть большой пост. Если не три.
     
  6. Rost_admin

    Rost_admin Нуб

    Почитал про таймеры, взял код из вашего примера

    Код (C++):
    mytimer = tmr.create()
    mytimer:register(5000, tmr.ALARM_SINGLE, function(t) print("Я таймер!") end)
    tmr.start(mytimer)
    [​IMG]
     
  7. ИгорьК

    ИгорьК Гуру

    Код (C++):
    mytimer:start()
     
  8. Rost_admin

    Rost_admin Нуб

    Получается синтаксис периодически меняется, я правильно понимаю. И лучше обращаться к "NodeMCU Documentation".

    Верно ?
     
  9. ИгорьК

    ИгорьК Гуру

    Ой, верно. Это всегда и везде верно.

    Но в данном случае это то ли баг то ли фича.
     
  10. Rost_admin

    Rost_admin Нуб

    Выполняю вот такой код:

    Код (C++):
    station_cfg={}
    station_cfg.ssid="NODE-AABBCC"
    station_cfg.pwd="password"
    station_cfg.save=true
    wifi.sta.config(station_cfg)
    Модуль не цепляется к WiFi. Как найти в чем проблема?
     
  11. ИгорьК

    ИгорьК Гуру

    Читать здесь и документацию. Таких детских вопросов в теме еще не было.
     
  12. ИгорьК

    ИгорьК Гуру

    47. Модуль MODBUS ESP32 и его применение для чтения PZEM-16. Часть 1.

    Вот оно, работает:

    SmartSelect_20191024-221049_Gallery.jpg

    upload_2019-10-24_19-1-44.png

    Модуль _modbus.lua:
    Код (Lua):
    local M = {}
    M.setup = function()
        if not M.set then
            M.set = true -- Признак установки порта в требуемый режим, чтобы лишний раз не дергать
            uart.setup(2, 9600, 8, uart.PARITY_NONE, uart.STOPBITS_1, {tx = 16, rx = 17})
            uart.start(2)
        end
    end
    -- Рабочие переменные
    local startUART = false -- Прием данных их УАРТ
    local gotuartt = {} -- Склад данных
    local startsg = 1 -- Значение первого байта для приема из УАРТ
    local lengthans = 100 -- Количество байт для приема
    local setuart -- Функция установки УАРТ (будет)
    local killtimer -- Таймер прерывания приема в случае утери устройства
    killtimer = tmr.create()

    -- Проверка/расчет контрольной суммы:
    local function crchex(dt, ok)
        local res = ''
        local crc = 0xFFFF
        local lowb, hihb
        -- Это признак проверки
        if ok then
            if type(dt) ~= 'table' then return false end
            -- Удаляем и запоминаем два последних байта - они контрольные
            lowb = table.remove(dt)
            hihb = table.remove(dt)
        end
        -- Непосредственный расчет
        for i = 1, #dt do
            crc = bit.bxor(crc, dt[i])
            for j = 0, 7 do
                if bit.band(crc, 1) > 0 then
                    crc = bit.rshift(crc, 1)
                    crc = bit.bxor(crc, 0xA001)
                else
                    crc = bit.rshift(crc, 1)
                end
            end
        end
        -- Добавляем в конец таблицы два расчитанных байта
        dt[#dt+1] = bit.band(crc, 0xFF)
        dt[#dt+1] = bit.rshift(crc, 8)

        -- Если проверка crc, то сравниваем два последних байта с теми,
        -- что изъяли ранее и возвращаем true/false
        if lowb then
            if dt[#dt-1] == hihb  and dt[#dt] == lowb then
                print('good crc')
                return true
            else
                print('bad crc')
                return false
            end
        end
        -- Если не проверка crc, возвращаем стринг с добавкой crc
        for i = 1, #dt do
            res = res..string.char(dt[i])
        end
        return res
    end

    -- Функция приема данных от УАРТ
    local function parcecom (t, gotuartt)
        -- Отменяем callback UARTa
        setuart()
        -- Останавливаем таймер реакции на ошибку
        t:stop()
        -- Проверяем crc
        local ok = crchex(gotuartt, true)
        if not ok then
            print('Lost Modbus Unit')
            return
        end
        --table.foreach(gotuartt, print)
        -- Вызываем полученный callback с передачей ему флага ошибки, табицы
        -- и ссылки на таймер
        if M.call then
            M.call(ok, gotuartt, t)
        end
    end

    -- Регистрация таймера обработки ошибки, принудительно парсим
    -- несуществующий ответ pzem-16
    killtimer:register(500, tmr.ALARM_SEMI, parcecom)

    -- Устанавливаем или отменяем callback на UART
    setuart = function(com)
        if com then
        startUART = false
        gotuartt = {}
        lengthans = 100 -- сначала избыточное количество байт для приема
        uart.on(2,"data",1,
            function(data)
                --print(string.byte(data))
                -- ждем появления байта startsg, который есть адрес опрашиваемого устройства
                if startUART == false and string.byte(data) ~= startsg then return
                elseif startUART == false then startUART = true end
                -- Появился адрес слэйва - начинаем собирать таблицу приема байтов
                gotuartt[#gotuartt+1] = string.byte(data)
                -- Третий байт из порта показывает сколько ждать байт
                if #gotuartt == 3 then
                    -- Устанавливаем количество принимаемых байт
                    lengthans = gotuartt[3] + 5
                end
                -- Наловили нужное число байт - отправляем в обработчик
                if #gotuartt == lengthans then
                    startUART = false
                    lengthans = 100
                    startsg = 1
                    return parcecom(killtimer, gotuartt)
                end
        end, 0)
        -- Если функция setuart без аргумента - отмена callback (чтения) UART
        else
            uart.on(2,"data")
        end
    end
    -- Опрос устройства, принимаем таблицу для чтения и callback
    M.askpzem = function(modtb, call)
        -- Вызов установки порта, если не установлен ранее
        if not M.set then M.setup() end
        -- Делаем внутреннюю ссылку на callback
        if call then M.call = call end
        -- Если не передавать таблицу - подставляем умолчание
        -- опрос pzem-16 с ардресом 0х01
        if type(modtb) ~= 'table' then modtb = {1,4,0,0,0,10} end
        -- Первый байт таблицы - он же старт приема UART
        startsg = modtb[1]
        -- Определяем callback на UART
        setuart('on')
        -- Вычисляем crc и формируем стринг на передачу устройству Modbus
        local ask = crchex(modtb)
        -- Печатаем что отправляем на устройство
        local u = ''
        for i = 1, #ask do
            u = u ..string.byte(ask, i, i)..', '
        end
        print('Ask: '..u)
        -- Запрос данных с pzem-16
        uart.write(2, ask)
        -- Запуск таймера обработки ошибки
        killtimer:start()
    end
    return M

    Как будем применять.
     
    Последнее редактирование: 14 июн 2020
    sashan нравится это.
  13. Rost_admin

    Rost_admin Нуб

    Я читаю, не могу понять. Даже в этой ветки несколько примеров и все разные. Я взял код прямо с документации.
     
  14. ИгорьК

    ИгорьК Гуру

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

    ИгорьК Гуру

    47. Модуль MODBUS ESP32 и его применение для чтения PZEM-16. Часть 2.
    Раньше.
    Для работы грузим в ESP32 два прилагаемых файла, запускаем вот этот, и получаем данные.

    Разъяснялки под спойлером.

    Код (Lua):
    -- Грузим модуль
    bus = require('_modbus')
    -- Итоговая таблица данных от pzem-016
    pzem = {}

    -- Callback, что будет передан в модуль
    -- Принимаем флаг успех/провал и таблицу с ответом pzem-016 , если она есть
    parce_pzem = function (ok, gotuartt)
        -- Провал? Прощай, детка!
        if not ok then
            print('Lost Modbus Unit')
            return
        end
        -- Так заполняем таблицу разной фигней, в частности - адрес pzem-016
        pzem.unit = gotuartt[1]
        --table.foreach(gotuartt, print)
        -- Напечатаем ответ pzem-016
        local raw = ''
        for i=1, #gotuartt do
            raw = raw..gotuartt[i]..', '
        end
        print(raw)

        -- Расчеты, что там может прислать pzem-016
        local calc = gotuartt[5]
        calc = calc + bit.lshift(gotuartt[4],8)
        pzem.volt = calc / 10
        print('\n\nVolt:', pzem.volt)
        if gotuartt[11] then
            calc = gotuartt[7] + bit.lshift(gotuartt[6],8) + bit.lshift(gotuartt[9],16) + bit.lshift(gotuartt[8],32)
            pzem.current = calc / 1000
            print('Current = ', pzem.current)
        end
        if gotuartt[15] then
            calc = gotuartt[11] + bit.lshift(gotuartt[10],8) + bit.lshift(gotuartt[13],16) + bit.lshift(gotuartt[12],32)
            pzem.power = calc / 10
            print('Power = ', pzem.power)
        end
        if gotuartt[19] then
            calc = gotuartt[15] + bit.lshift(gotuartt[14],8) + bit.lshift(gotuartt[17],16) + bit.lshift(gotuartt[16],32)
            pzem.energy = calc
            print('Energy = ', pzem.energy)
        end
        if gotuartt[21] then
            calc = gotuartt[19] + bit.lshift(gotuartt[18],8)
            pzem.frequency = calc/10
            print('Frequency = ', pzem.frequency)
        end
    end
    -- Callback, что выше - готов, пора спрашивать pzem-016!
    bus.askpzem(false, parce_pzem)

    -- {0x01, 0x42} -- reset energy
    -- {0x01, 0x06, 0x00, 0x02, 0x00, 0x02} -- change address to 0x02

    -- Сброс энергетики:
    -- bus.askpzem({0x01, 0x42})
    -- Изменение адреса устройства с 0x01 на 0x02
    -- bus.askpzem({0x01, 0x06, 0x00, 0x02, 0x00, 0x02})

    Внимательно читаем комментарии, и узнаем как делать пару дополнительных вещей - сбрасывать данные и менять адрес pzem-016.
     

    Вложения:

    • modbus.zip
      Размер файла:
      1,7 КБ
      Просмотров:
      385
    Последнее редактирование: 28 окт 2019
  16. ИгорьК

    ИгорьК Гуру

    48. Связь с брокером с уничтожением неудачного соединения. ESP8266.

    Код mqttset.lua:
    Код (Lua):
    do
        local subscribe, merror, newm, mconnect
        -- Забираем в локальные переменные брокер и порт
        local brk = dat.brk
        dat.brk = nil
        local port = dat.port
        dat.port = nil

        -- После соединения:
        function subscribe(con)
            print("Connected")
            -- Всем знать что соединениет есть
            dat.broker = true
            -- Подписка на командный топик
            con:subscribe(dat.clnt.."/com/#", 0)
            -- Публикуем состояние жизни
            con:publish(dat.clnt..'/state', "ON", 0, 1)
            print("Subscribed")
        end
     
        -- Ошибка соединения
        function merror(con, reason)
            print('Function Error! Heap: ', node.heap())
         
            -- Уничтожаем предыдущее соединение
            con = nil
            reason = nil
            m = nil
            collectgarbage()
         
            -- Пересоединение через 10 секунд
            tmr.create():alarm(10000, tmr.ALARM_SINGLE, function(t)
                t = nil
                mconnect(newm())
            end)
        end

        -- Создаем новый объект соединения
        function newm()
            m = mqtt.Client(dat.clnt, 25, dat.clnt, 'pass22')
            m:lwt(dat.clnt..'/state', "OFF", 0, 1)
            m:on("offline", function(con)
                con:close()
                dat.broker = false
                print("Offline")
                merror(con)
            end)
            m:on("message", function(con, top, dt)
                if not killtop then killtop = {} end
                top = string.match(top, "/(%w+)$")
                print('Got', top, dt)
                if dt then
                    table.insert(killtop, {top, dt})
                    if not dat.analiz then
                        dofile("mqttanalize.lua")
                    end
                end
            end)
            return m
        end
        -- Функция соединения, где в качестве аргумента - новый объект
        function mconnect(con)
            con:connect(brk, port, false, subscribe, merror)
        end
        mconnect(newm())
    end
    Для работы - приложение.
     

    Вложения:

    • AmperkaMQTT.zip
      Размер файла:
      621,6 КБ
      Просмотров:
      356
    swc нравится это.
  17. za9c

    za9c Нуб

    Гуру NodeMCU подскажите - есть такая команда
    wifi.suspend(), которая приостанавливает работу wi-fi.
    Но она по умолчанию отключена и для того, чтобы включить нужно прописать PMSLEEP_ENABLE в app/include/user_config.h

    Так вот вопрос?
    Как Вы это пропись делаете? или обязательно на си свой огород городить с нуля? можно ли вклиниться в прошивку сделанную конструктором с сайта https://nodemcu-build.com/ ?

    Смысл в чём - проснулся, считал информацию с датчика, сохранил в памяти и так каждую минуту - раз в час - передал по сети пакет с данными.
     
    Последнее редактирование: 16 ноя 2019
  18. ИгорьК

    ИгорьК Гуру

    49. Проект ESP32 - Ajax Systems.

    Здесь. Можно посмотреть некоторые нюансы работы с UART.
     
    swc нравится это.
  19. AlsPro

    AlsPro Нерд

    Приветствую! Не могу понять, почему данные передаются только в 1 сторону?
    Загрузил в 2 ESP8288 клиента и сервер
    Вот код сервера
    Код (C++):
    print("ESP8266 Server")  --  "Сервер ESP8266"
    wifi.setmode(wifi.SOFTAP);
    wifi.ap.config({ssid="Dynamo",pwd="dynamo77"});
    print("Server IP Address:",wifi.ap.getip())  --  "IP-адрес сервера:"


    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("hello world")
      end)
    end
     
    а вот клиент
    Код (C++):

    srv = net.createConnection(net.TCP, 0)
    srv:on("receive", function(srv, rr)
        print(rr)
        srv:close()
        end)
    -- Wait for connection before sending.
    srv:on("connection", function(srv)

      srv:send("1211")
    end)

    srv:connect(80,"192.168.4.1")

     srv:on("disconnection", function(srv) end)
     
    В итоге с клиента на сервер я данные получаю, а в обратную сторону нет.
    Подскажите, в чем проблема?
     
    Последнее редактирование: 28 ноя 2019
  20. ИгорьК

    ИгорьК Гуру

    В callback сервера.