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

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

  1. ketusur

    ketusur Нуб

    Бывает, отваливается какой-то датчик, но его данные остаются в «мозгах» часов. Температура повышается, а часы продолжают работать со старым МРОТ. Логично проверять время последнего обновления сенсора и уничтожать данные, если время превышено. Итак, в лоб, в часах и готово.
    guest survey Restaurant Survey
     
  2. obuhanoe

    obuhanoe Гик

    Тему создал https://forum.amperka.ru/threads/esp32-модуль-http-nodemcu-утечка-памяти.23230/, нужно перенести сообщения начиная с https://forum.amperka.ru/threads/es...зы-программирования.12558/page-64#post-304590 (а тут почистить)
    Кто сможет это сделать?
     
  3. obuhanoe

    obuhanoe Гик

    Подскажите по захватам в версии 5.1
    пытаюсь получить данные из такой длинного ответа:
    Код (Text):
    answ = '{"ok":true,"result":[{"update_id":86345,"message":{"message_id":294,"from":{"id":70014,"is_bot":false,"first_name":"Oleg","language_code":"ru"},"chat":{"id":7652804,"first_name":"Oleg","type":"private"},"date":1671091987,"text":"#conf4_run","entities":[{"offset":0,"length":10,"type":"hashtag"}]}}]}'
    text = string.match(answ, '"text":"(.-)"');
    print ('text = ', text)
    В онлайн редакторах (на сайтах) код верный, данные получаю как и ожидаю..
    Еще проверил в программе zbstudio.exe (Lua 5.1-5.3) - тоже работает.
    Если проверять в ESplorer - получаю ошибку:
    Код (Text):
    Lua error:     stdin:1: unfinished string near '"}]}}]}''print ('text = ', text2)
     
    Слишком длинная строка ?
     
  4. ИгорьК

    ИгорьК Гуру

    Похоже. Если уменьшить строку - работает.
     
  5. ИгорьК

    ИгорьК Гуру

    Попробуйте там где вы его добываете выполнить:

    Код (Lua):
    answ = '{"ok":true,"result":[{"update_id":86345,"message":{"message_id":294,"from":{"id":70014,"is_bot":false,"first_name":"Oleg","language_code":"ru"},"chat":{"id":7652804,"first_name":"Oleg","type":"private"},"date":1671091987,"text":"#conf4_run","entities":[{"offset":0,"length":10,"type":"hashtag"}]}}]}'

    --------------------
    local i, j = string.find(answ, 'private')
    if i then
       answ = string.sub(answ, j+1, -1)
    end
    ---------------------

    text = string.match(answ, '"text":"(.-)"')
    print ('text = ', text)
     
    obuhanoe нравится это.
  6. obuhanoe

    obuhanoe Гик

    Да, это тоже заметил - уменьшаю длину все работает.
    Ошибка сохраняется, видимо методы string (find/match) не могут переварить длину строки.

    Но я это делаю в окне слева и отправляю в ESP кнопкой "Block". Заведу код во внутрь lua файла и после отпишусь.

    P.S.
    А Ларчик то открылся - проблема это ESPlorer и окна отправки Block.
    Если сохранить lua скрипт в память eSP то работает вариант Игоря и мой изначальный.
    Игорь еще раз спасибо за помощь.
     
    Последнее редактирование: 16 дек 2022
    ИгорьК нравится это.
  7. ИгорьК

    ИгорьК Гуру

    Класс! Полезно будет знать.
     
    obuhanoe нравится это.
  8. obuhanoe

    obuhanoe Гик

    Подскажите по такому вопросу:
    вызываю метод с callback:
    Код (Text):
    http.get(curl, function(code, data)

    ... какой-то код

    end)
    Ловлю ошибку (появляется очень хаотично):
    attempt to call a number value
    stack traceback:

    после stack traceback: - уже информация о загрузке ESP32.

    и модуль (ESP32, Lua 5.1 IDF 4.4) перегружается - можно как то отловить место ошибки?
    Обложим код print - не помогает ((

    P.S. также попробовал http.post - ошибка тоже хаотичная и точно такая же.
     
  9. serg3295

    serg3295 Гуру

    Для поиска случайных ошибок в callback и причинах рестартов можете воспользоваться таким кодом. Он для 8266, поэтому перепишите под io
    Код (C++):
    local function catchErr()

      local tn = rtctime.epoch2cal(rtctime.get()+10800)
      file.open("boot.txt",  "a+")
      local _, reason, exccause, epc1, epc2, epc3, excvaddr, depc = node.bootreason()
      exccause = exccause or 0
      epc1 = epc1 or 0
      epc2 = epc2 or 0
      epc3 = epc3 or 0
      excvaddr = excvaddr or 0
      depc = depc or 0
      file.write(string_format('%02d:%02d:%02d %d,%d,%d,%d,%d,%d,%d', tn.hour, tn.min, tn.sec, reason, exccause, epc1, epc2, epc3, excvaddr, depc)..'\n')
      file.close()
      tn = nil

      node.setonerror(function(s)
        file.open("err.txt",  "a+")
        file.write('\nERROR '..s)
        file.close()
        node.restart()
      end)

    end
     
     
    ИгорьК нравится это.
  10. ИгорьК

    ИгорьК Гуру

    Там перед ребутом может быть такая малозаметная строчка:
    Е:М 306
    Не обнаруживали?
     
  11. obuhanoe

    obuhanoe Гик

    не наблюдал ранее и сейчас тоже
    Код (Text):
    -- начало ошибки
    attempt to call a number value
    stack traceback:
    -- МОЙ КОД
    TYT_5_1
    TYT_2
    200    {"ok":true,"result":[]}
    TYT_3
    -- МОЙ КОД
    I (797046) wifi:state: run -> init (0)
    I (797046) wifi:pm stop, total sleep time: 622539555 us / 773458196 us

    W (797046) wifi:<ba-del>idx
    W (797046) wifi:<ba-del>idx
    I (797046) wifi:new:<13,0>, old:<13,2>, ap:<255,255>, sta:<13,2>, prof:1
    WIFI DISCONNECTED!!!
    W (797066) wifi:hmac tx: ifx0 stop, discard
    I (797226) wifi:flush txq
    I (797226) wifi:stop sw txq
    I (797226) wifi:lmac stop hw txq
    ets Jun  8 2016 00:22:57

    rst:0xc (SW_CPU_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
    configsip: 0, SPIWP:0xee
    clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
    mode:DIO, clock div:2
    load:0x3fff0030,len:6660
    load:0x40078000,len:14848
    ho 0 tail 12 room 4
    load:0x40080400,len:3792
    entry 0x40080694
    [0;32mI (29) boot: ESP-IDF v4.4.2 2nd stage bootloader[0m
    [0;32mI (29) boot: compile time 13:49:47[0m
    [0;32mI (29) boot: chip revision: 0[0m
    [0;32mI (32) boot.esp32: SPI Speed      : 40MHz[0m
    [0;32mI (36) boot.esp32: SPI Mode       : DIO[0m
    [0;32mI (41) boot.esp32: SPI Flash Size : 4MB[0m
    [0;32mI (45) boot: Enabling RNG early entropy source...[0m
    [0;32mI (51) boot: Partition Table:[0m
    [0;32mI (54) boot: ## Label            Usage          Type ST Offset   Length[0m
    [0;32mI (62) boot:  0 nvs              WiFi data        01 02 00009000 00006000[0m
    [0;32mI (69) boot:  1 phy_init         RF data          01 01 0000f000 00001000[0m
    [0;32mI (77) boot:  2 factory          factory app      00 00 00010000 00180000[0m
    [0;32mI (84) boot:  3 lfs              unknown          c2 01 00190000 00010000[0m
    [0;32mI (92) boot:  4 storage          Unknown data     01 82 001a0000 00070000[0m
    [0;32mI (99) boot: End of partition table[0m
    [0;32mI (103) esp_image: segment 0: paddr=00010020 vaddr=3f400020 size=25d84h (155012) map[0m
    [0;32mI (168) esp_image: segment 1: paddr=00035dac vaddr=3ffb0000 size=03748h ( 14152) load[0m
    [0;32mI (174) esp_image: segment 2: paddr=000394fc vaddr=40080000 size=06b1ch ( 27420) load[0m
    [0;32mI (185) esp_image: segment 3: paddr=00040020 vaddr=400d0020 size=bad64h (765284) map[0m
    [0;32mI (462) esp_image: segment 4: paddr=000fad8c vaddr=40086b1c size=0f880h ( 63616) load[0m
    [0;32mI (489) esp_image: segment 5: paddr=0010a614 vaddr=400c0000 size=00064h (   100) load[0m
    [0;32mI (489) esp_image: segment 6: paddr=0010a680 vaddr=50000000 size=00010h (    16) load[0m
    [0;32mI (505) boot: Loaded app from partition at offset 0x10000[0m
    [0;32mI (506) boot: Disabling RNG early entropy source...[0m
    [0;32mI (517) cpu_start: Pro cpu up.[0m
    [0;32mI (518) cpu_start: Starting app cpu, entry point is 0x400814ac[0m
    [0;32mI (504) cpu_start: App cpu up.[0m
    [0;32mI (534) cpu_start: Pro cpu start user code[0m
    [0;32mI (534) cpu_start: cpu freq: 160000000[0m
    [0;32mI (534) cpu_start: Application information:[0m
    [0;32mI (539) cpu_start: Project name:     nodemcu[0m
    [0;32mI (544) cpu_start: App version:      1.4.0-master_20151229-860-ged85[0m
    [0;32mI (551) cpu_start: Compile time:     Nov 23 2022 13:49:37[0m
    [0;32mI (557) cpu_start: ELF file SHA256:  6fcaa6c47ac702bc...[0m
    [0;32mI (563) cpu_start: ESP-IDF:          v4.4.2[0m
    [0;32mI (568) heap_init: Initializing. RAM available for dynamic allocation:[0m
    [0;32mI (575) heap_init: At 3FFAE6E0 len 00001920 (6 KiB): DRAM[0m
    [0;32mI (581) heap_init: At 3FFB7C70 len 00028390 (160 KiB): DRAM[0m
    [0;32mI (587) heap_init: At 3FFE0440 len 00003AE0 (14 KiB): D/IRAM[0m
    [0;32mI (593) heap_init: At 3FFE4350 len 0001BCB0 (111 KiB): D/IRAM[0m
    [0;32mI (600) heap_init: At 4009639C len 00009C64 (39 KiB): IRAM[0m
    [0;32mI (607) spi_flash: detected chip: gd[0m
    [0;32mI (610) spi_flash: flash io: dio[0m
    [0;32mI (616) cpu_start: Starting scheduler on PRO CPU.[0m
    [0;32mI (0) cpu_start: Starting scheduler on APP CPU.[0m
    [0;32mI (626) uart: queue free spaces: 3[0m

    No LFS image loaded
    I (726) wifi:wifi driver task: 3ffc58dc, prio:23, stack:6656, core=0
    [0;32mI (726) system_api: Base MAC address is not set[0m
    [0;32mI (726) system_api: read default base MAC address from EFUSE[0m
    I (746) wifi:wifi firmware version: eeaa27d
    I (746) wifi:wifi certification version: v7.0
    I (746) wifi:config NVS flash: enabled
    I (746) wifi:config nano formating: disabled
    I (746) wifi:Init data frame dynamic rx buffer num: 32
    I (756) wifi:Init management frame dynamic rx buffer num: 32
    I (756) wifi:Init management short buffer num: 32
    I (766) wifi:Init dynamic tx buffer num: 32
    I (766) wifi:Init static rx buffer size: 1600
    I (766) wifi:Init static rx buffer num: 10
    I (776) wifi:Init dynamic rx buffer num: 32
    [0;32mI (776) wifi_init: rx ba win: 6[0m
    [0;32mI (786) wifi_init: tcpip mbox: 32[0m
    [0;32mI (786) wifi_init: udp mbox: 6[0m
    [0;32mI (786) wifi_init: tcp mbox: 6[0m
    [0;32mI (796) wifi_init: tcp tx win: 5744[0m
    [0;32mI (796) wifi_init: tcp rx win: 5744[0m
    [0;32mI (796) wifi_init: tcp mss: 1436[0m
    [0;32mI (806) wifi_init: WiFi IRAM OP enabled[0m
    [0;32mI (806) wifi_init: WiFi RX IRAM OP enabled[0m
    No LFS image loaded

    NodeMCU ESP32 build unspecified powered by Lua 5.1.4 [5.1-doublefp] on IDF v4.4.2
    cannot open init.lua: No such file or directory
     
    Спасибо за код, перепишу под io.
    Вопрос только куда этот код встроить во внутрь callback?
     
  12. ИгорьК

    ИгорьК Гуру

    Похоже, вы делаете запрос к серверу, и по получении ответа вызываете некий callback? Иногда это все валится и непонятна причина.

    Причина может быть в том, что:
    - ответ иногда приходит с большим запозданием;
    - ответ вообще не приходит.

    Дальше начинает исполняться какой-то код, что перегружает память. Возможно и такое - наступает время нового запроса, а сокет у вас не закрыт.

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

    Я с таким столкнулся в проекте часов. Там постоянно идут обращения к серверам и раз в три-четыре часа возникают проблемы. Как я решаю это:

    Код (Lua):

    cb_disconnected = function(c)
        pcall(function() conn:close() end)
         c, conn = nil, nil
    end

    data_received = function(c, data)
        if killask then killask:stop(); killask:unregister(); killask = nil end
       -------------
       -- code
       ------------
       cb_disconnected(c)
    end

    if wifi.sta.status() == 5 then
        net.dns.resolve("api.openweathermap.org", function(sk, ip)
            if (ip == nil) then
                print("Lost DNS openweathermap!")
            else
                killask = tmr.create()
                killask:alarm(2000, 0, function(_)
                    if conn then
                        cb_disconnected()
                        print('\n\nConn killed!\n\n')
                    end
                end)
                conn = net.createConnection(net.TCP, 0)
                conn:on("connection", function(conn, payload) conn:send(request.."Connection: close\r\nAccept: /\r\n\r\n") end)
                conn:on("disconnection", cb_disconnected)
                conn:on("receive", data_received)
                conn:connect(80, 'api.openweathermap.org')
            end
        end)
    end
    Можно получше сделать, но так тоже работает, не жрет регистр и не плодит кучу, проверено.
     
    Последнее редактирование: 26 дек 2022
    obuhanoe нравится это.
  13. obuhanoe

    obuhanoe Гик

    я использую hhtp.get - который не возвращает параметров, поэтому и нечего закрывать соединение.
    попробовал использовать options (http.get(url, [options,] [callback])) timeout - тоже не помогает.
    Попробовал перейти (точнее вернуться) на net.createConnection
    Код (Text):
    do

        local srv = net.createConnection(net.TCP, 0)  
        srv:on("connection", function(sck, c)          
            sck:send("GET /botXXXXXXX/getUpdates?offset=0  Connection: close\r\nAccept: */*\r\n\r\n")
        end)
       
        srv:on("receive", function(sck, c)
              print("D_DATA ", sck, c)          
        end)
       
        srv:connect(80,"api.telegram.org")
       
    end
    но телеграмм ругается -
    Код (Text):
    <head><title>400 Bad Request</title></head>

    <body bgcolor="white">

    <center><h1>400 Bad Request</h1></center>

    <hr><center>nginx/0.3.33</center>

    </body>

    </html>

     
    Возможно я ошибаюсь и неверно указываю Get-запрос
     
  14. ИгорьК

    ИгорьК Гуру

    К телеграму надо обращаться с применением tls и не по 80 порту, ИМХО.

    Где-то у меня здесь была тема на тему телеграм, поищите.
     
  15. ИгорьК

    ИгорьК Гуру

    Или так.

    Код (Lua):
    headers = {
      Connection = "close",
    }
    local timeNow = time.get()
    connection = http.createConnection("https://api.telegram.org/bot111111:BBBBBBBBBBBB-CCCCCCCCCCC/sendMessage?chat_id=11111111111&text=TestESP:"..(time.get()), http.GET, { headers=headers } )

    connection:on("data", function(status, data)
      print(data)
    end)
    connection:on("complete", function(status)
      print("Request completed with status code =", status)
    end)
     
    obuhanoe нравится это.
  16. obuhanoe

    obuhanoe Гик

    Получилось и у меня теперь, ранее пробовал и этот способ http.Get, только без headers - поэтому ранее и не получалось.

    Большое спасибо.
     
    ИгорьК нравится это.
  17. bor1andrey@gmail

    bor1andrey@gmail Нерд

    Добрый день. Есть необходимость в колбеке према UART заполнять некий буфер, а уже по таймеру его разгребать.
    Попытался сделать это так:

    Код (Lua):

    uartRxBuff = ""

    do
    uart.on("data", '\n', function(uartRxData)
      uartRxBuff = uartRxBuff .. uartRxData
    end, 0)

    tmr.create():alarm(1000, tmr.ALARM_AUTO, function()
      print("Response: ".. uartRxBuff)
      print("Uptime="..tmr.time().."s")
      uartRxBuff = ""
    end)
    end
     
    Код отрабатывает 1 раз и все, как будто очистка буфера в коде таймера запрещает дальнейшую запись в буфер внутри колбека.
     
    Последнее редактирование: 11 янв 2023
  18. ИгорьК

    ИгорьК Гуру

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

    Смотрите сюда, сюда.

    Чисто теоретически ваш код должен работать, но он не имеет смысла, чтобы ковыряться в нем.

    УАРТ отправляет какие-то упорядоченные данные, и они "ловятся" по прибытию, а не по времени.
     
  19. bor1andrey@gmail

    bor1andrey@gmail Нерд

    Благодарю за развернутый ответ.
    Обязательно почитаю указанный материал. У меня просто связь с радиомодулем посредством АТ-команд. И каждый ответ модуля заканчивается \r\n, но наличие этого маркера ещё совсем не означает что модуль полностью ответил, там в ответе может быть много параметров строк, каждая из которых имеет такое окончание. Но разбирать пакет имеет смысл только после принятие ВСЕГО этого хозяйства. Поэтому и была выбрана такая концепция: пульнуть команду модулю, ответ по каждому \n пихать в буфер, а когда дотикал таймаут, разгребать.
     
  20. ИгорьК

    ИгорьК Гуру

    Каждую эту последовательность отлавливаете и вызываете обработчик ответа с очисткой буфера. Анализ ответа происходит мгновенно, относительно скорости прихода данных в УАРТ. И так обрабатывается каждая посылка.

    Память то тоже не резиновая, кроме обработки УАРТ надо ещё что-то делать, не так ли.