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

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

  1. 8bitai

    8bitai Нерд

    Дело в том что указанный мной выше код телнетд работал и работает до сихпор на всех моих модулях с старой фирмваре версий 2.1.х
    я просто не заметил что они что-то меняли связанное с телнет начиная с 3.0.х
    однако этот новый код какой теперь среди стандартных луамодулей работает не так как ожидается
    Код (C++):

    localfunctiontelnet_session(socket)
        localnode=node
        localstdout

        localfunctionoutput_CB(opipe) -- upval: socket
            stdout=opipe
            localrec=opipe:read(1400)
            ifrecand#rec>0then
                socket:send(rec)
            end
            returnfalse-- don't repost as the on:sent will do this
        end

        localfunctiononsent_CB(skt) -- upval: stdout
            localrec=stdout:read(1400)
            ifrecand#rec>0then
                skt:send(rec)
            end
        end

        localfunctiondisconnect_CB(skt) -- upval: socket, stdout
            node.output()
            socket, stdout=nil, nil     -- set upvals to nl to allow GC
        end

        node.output(output_CB, 0)
        socket:on("receive", function(_, rec) node.input(rec) end)
        socket:on("sent", onsent_CB)
        socket:on("disconnection", disconnect_CB)
        print(("Connected to IU006 build 310523.  (%d mem free, %s)"):format(
            node.heap(), wifi.sta.getip()))
    end
    net.createServer(net.TCP, 180):listen(23, telnet_session)

    привиденная высше его часть отличается выкинутым куском с инициализацией вайфай и модульным оформлением
    в остальном это тотже код и выводит он данные так
    upload_2023-6-1_13-34-20.png
    вместо ожидаемых вот так
    upload_2023-6-1_13-35-45.png
    хотя старый код телнетд сервера с добавленной этой строчкой
    выводит ивыводил всё по человечески.
    Тоесть теперь другой вопрос как заставить текущий код выводить данные в гипертерминал почеловечески?



    Нет я ничем таким пока не пользовался потому как всякие форматёры вставляют ненужные пробелы какие ничего кроме потери памяти не несут, но прошу простить если запостил сюда неформатированый код,постараюсь посылать только форматированый.
     
    Последнее редактирование: 1 июн 2023
  2. serg3295

    serg3295 Гуру

    может это поможет.
    Putty -> Terminal -> Implicit CR in every LF

    Никаких вопросов к виду вашего кода не возникало.
    Просто почему-то про эту возможность написал. Даже не знаю зачем.:confused:
     
    8bitai нравится это.
  3. 8bitai

    8bitai Нерд

    Странно даже обычный линуксовский телнет клиент выводит всё правильно без всякой модификации кода сервера
    upload_2023-6-1_19-7-51.png
    никогда не сталкивался чтоб хипертерминал что-то неправильно выводил , обычно бывало что если он не выводит нормально ни с какими сетнгами опций терминала то и никакие другие клиенты ничего выводить нормально небудут :)
     
  4. 8bitai

    8bitai Нерд

    Другой вопрос,
    поднимаю сервер через dofile("minitelnet.lua")
    Код (C++):

    localfunctiontelnetd(socket)
        localnode=node
        localstdout
        localfunctionoutput_CB(opipe)
            stdout=opipe
            localrec=opipe:read(1400)
            ifrecand#rec>0then
                socket:send(rec)
            end
            returnfalse
        end
        localfunctiononsent_CB(skt)
            localrec=stdout:read(1400)
            ifrecand#rec>0then
                skt:send(rec)
            end
        end
        localfunctiondisconnect_CB(skt)
            node.output()
            socket, stdout=nil, nil
        end
        node.output(output_CB, 0)
        socket:on("receive", function(_, rec) node.input(rec) end)
        socket:on("sent", onsent_CB)
        socket:on("disconnection", disconnect_CB)
        print(("Connected to Node125 build 310523.  (%d mem free, %s)"):format(node.heap(), ST_ip))
    end
    net.createServer(net.TCP, 180):listen(23, telnetd)
     
    то всё работает.
    если поднимаю как модуль вот так:
    net.createServer(net.TCP, 180):listen(23, function(c) require("minitelnet").telnetd()end)
    Код (Text):

    do
        localmm=...
        print(mm)
        localM= {}
        functionM.telnetd(socket)
            localnode=node
            localstdout
            localfunctionoutput_CB(opipe)
                stdout=opipe
                localrec=opipe:read(1400)
                ifrecand#rec>0then
                    socket:send(rec)
                end
                returnfalse
            end
            localfunctiononsent_CB(skt)
                localrec=stdout:read(1400)
                ifrecand#rec>0then
                    skt:send(rec)
                end
            end
            localfunctiondisconnect_CB(skt)
                node.output()
                socket, stdout=nil, nil
            end
            node.output(output_CB, 0)
            socket:on("receive", function(_, rec) node.input(rec) end)
            socket:on("sent", onsent_CB)
            socket:on("disconnection", disconnect_CB)
            print(("Connected to Node125 build 310523.  (%d mem free, %s)"):format(node.heap(), ST_ip))
        end

        --net.createServer(net.TCP, 180):listen(23, telnetd)
        returnM
    end



     
    то один и тот же сервер подниматься нежелает
    (18360 mem free, 192.168.0.228)

    IndexCNT: 6
    minitelnet
    PANIC: unprotected error in call to Lua API (minitelnet.lua:27: attempt to index a nil value)
    вроде почитал как поднимать модули немогу понять где ошибся.
     
    Последнее редактирование: 7 июн 2023
  5. ИгорьК

    ИгорьК Гуру

    Тоже интересно почитать.

    Код (Lua):
    net.createServer(net.TCP, 180):listen(23, function(c) require("minitelnet").telnetd()end)
    Какой же Иерусалимски тупой: никогда не видел у него такого крутого кода.
    Нинавижупрограммистав.
     
    8bitai и serg3295 нравится это.
  6. serg3295

    serg3295 Гуру

    "Больше всего комиссию поразило, что вы разобрали двигатель через выхлопную трубу." (с)из анекдота.

    net.createServer(180):listen(23, require("minitelnet").telnetd)
    Остальную кучу ошибок я не исправлял.
     
    8bitai и ИгорьК нравится это.
  7. 8bitai

    8bitai Нерд

    В теме
    азы программирования.
    например :)

    Код (Lua):
    net.createServer(net.TCP, 180):listen(23, function(c) require("minitelnet").telnetd()end)
    и тут же можно встретить то что не встречалось у Иерусалимски.
    Не лукавьте, такие темы и с таким названием из ненависти к самому себе не инициируют...
    поторопился я писать, ну а почему мне стесняться если я не знаю?
    это непонятно что если человек в азы попал значит возможно не знает - чего так угорать то?:)
    вот эта стандартная колбаса
    Код (C++):
    local M={}
    local mn = ...
    print(mn)
    local function telnetd(socket)
    local node=node
    local stdout
    local function output_CB(opipe)
    stdout=opipe
    local rec=opipe:read(1400)
    if rec and #rec > 0 then socket:send(rec)end
    return false
    end
    local function onsent_CB(skt)
    local rec=stdout:read(1400)
    if rec and #rec > 0 then skt:send(rec)end
    end
    local function disconnect_CB(skt)
    node.output()
    socket,stdout=nil,nil
    end
    node.output(output_CB, 0)
    socket:on("receive", function(_,rec) node.input(rec)end)
    socket:on("sent", onsent_CB)
    socket:on("disconnection", disconnect_CB)
    print(("Node125 Ready: (%d mem free, %s)"):format(node.heap(),ST_ip))
    end
    function M.open(this,ssid,pwd,port)
    local tmr,wifi,uwrite=tmr,wifi, uart.write
    if ssid then
    wifi.setmode(wifi.STATION, false)
    wifi.sta.config { ssid=ssid,pwd=pwd,save=false }
    end
    local t=tmr.create()
    t:alarm(500, tmr.ALARM_AUTO,function()
    if (wifi.sta.status()==wifi.STA_GOTIP) then
    t:unregister()
    t=nil
    print(("Telnet server started (%d mem free, %s)"):format(node.heap(),ST_ip))
    M.svr=net.createServer(net.TCP, 180)
    M.svr:listen(port or 23, telnetd)
    else
    uwrite(0,".")
    end
    end)
    end
    function M.close(this)
    if this.svr then this.svr:close()end
    package.loaded[mn]=nil
    end
    return M
     


    запустилась!

    вот так
    local telnet=require("telnet")
    telnet:eek:pen(nil, nil, 12323)
    совсем как по учебнику?
    upload_2023-6-7_23-51-47.png
    или прям как тут?
    upload_2023-6-7_23-54-9.png
    я всего-то хотел её укоротить вычистив ненужное и запустить модулем
    почти получилось запуская ду файлом, а как то что получилось представить в виде модуля не понимаю.
    помогите если возможно.
     
  8. serg3295

    serg3295 Гуру

    А та строчка кода для запуска, которую я написал, не помогла?
    И никто не угорает. Речь идёт об упрощении кода, особенно на этапе отладки.
    Выводя через print результаты require, выделенный в отдельную строку, вы бы сами нашли ошибку
     
    8bitai нравится это.
  9. 8bitai

    8bitai Нерд

    Остальную кучу ошибок упустив все пробелы допустил упомянутый форматер
    изначально мой шедевр запускающийся дуфайлом выглядел до копипацты вот так
    upload_2023-6-8_0-16-53.png
    а не запускающийся как модуль вот так
    upload_2023-6-8_0-18-46.png
     
  10. 8bitai

    8bitai Нерд

    я её увидел уже после того как стандартную колбасу запустил, щас попробую вашу строчку...
    А что нетак с упрощением кода даже если на этапе отладки?
    предполагается и я в этом убедился что неупрощенный код работает, но он меня не устроил наличием приблуды проверки на подключение вайфай, потому стал его чикать как мог.

    Это как? неуверен что понял..

    а какую кучу ошибок?
    ваша строчка
    net.createServer(180):listen(23, require("minitelnet").telnetd)
    также отлично сработала с моей урезаной версией кода! большое спасибо.
    выглядит она очень просто и логично
    я вроде пытался тыркануть тоже самое до всевозможных танцев с бубном в последней версии с (c)...
     
    Последнее редактирование: 8 июн 2023
  11. ИгорьК

    ИгорьК Гуру

    Вы гоните такую кучу кода, что прям грустно.

    Когда кода много, его надо комментировать с целью понять что там происходит.
    И тот кусок вырви-глаз, что я процитировал - он для просветленных программистов, к коим я лично не отношусь. Поэтому, наряду с комментариями правильно иметь локальные переменные, через которые все упрощается и понимается.

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

    Почему бы вам не пытаться сделать это самому, вместо "вот многа кода и он не работает"?

    ПыСы. Я люблю MQTT и работаю с ним и только с ним.
    ПыПыСы. А еще мне нравится NodeRed в связке с MQTT. Это решает много вопросов.
     
    Последнее редактирование: 8 июн 2023
    8bitai нравится это.
  12. 8bitai

    8bitai Нерд

    А я извиняюсь что загрузил , просто подействовала так шапка темы и то как вы и все помогавшие всё красиво разложили по полочкам в этой теме ну плюс статус гуру тоже подействовал никак не предполагал что никто не разбирася в текущем стандартном текущем коде телнет сервера.
    До MQTT пока недобирался , года 2 назад понаделал себе кучку уродцев с прикрученым телнет сервером для определённых целей
    на старой прошивке 2.х.х все работает но мне понравились некоторые нововведения 3.х.х и я решил прикинуть пока как бы перевести всех уродцев на неё но столкнулся с изменениями в телнет коде (я их уже упоминал), кроме того по причине простоты использованных решений никогда нехватки памяти неиспытывал даже без использования техник с загрузкой выгрузкой модулей кроме работы с 18дс20 и не вникал в то как это в действительности работает также только разобрался как на неандертальском уровне пользоваться ЛФС
    Ещё раз прошу простить не хотел что б выглядело именно так "вот многа кода и он не работает", но действительно выглядит именно так :)
     
  13. ИгорьК

    ИгорьК Гуру

    Я не знаю для чего в хозяйстве нужен телнет. Устройства наши маленькие и должны работать сразу, без планирования постоянного обновления прошивки. Это не винда и не пингвин.

    Для обмена информацией лучше MQTT нет. Я как-то писал заметку об этом на своём сайте.

    Я понимаю ваш код где анонимная функция сидит в анонимный функции и оной погоняет. Но без обращения к документации не могу разобраться что там к чему.

    Когда я вижу такой код в принципе, то вижу два варианта, один хуже другого.

    Либо это притащили чужой код и без понятия как он работает. Либо начинающий написал его сам, но это жуть как творчески и человек Иерусалимски через себя не пропустил. Мэтр не делает таких конструкций (хотя язык это позволяет).
     
  14. ИгорьК

    ИгорьК Гуру

    Сергей вам показал телнет.
     
  15. 8bitai

    8bitai Нерд

    Сергей показал модификацию стандартного телнет модуля написанного возможно одним из авторов NODEMCU лежащего в каталоге Lua Modules прошивки
    еслиб вам довелось краем глаза глянуть хотябы на то что дал Сергей и что из себя представляет этот стандартный с 2019 ого года модуль вам былобы это понятно.
    Таким образом когда вы говорите "когда я вижу такой код" несовсем понятно какой именно код вы подразумиваете?
    оригинальный код практически без изменений приводил Сергей и он лежит тут
    upload_2023-6-8_8-26-10.png
    разумеется я этот код не писал и не дополнял а только урезал.В папке lua_modules прошивки очень много чужого кода какой написали именно с той целью чтоб другие могли им както воспользоваться.
    Хочу заметить это даже не папка Lua_examles а именно стандартные луа модули какие предполагается поддерживает текущая прошивка.
    Код представлен в виде модуля и по какойто причине снабжон удлинняющей его опцией проверки подключенности устройства в сеть какая в принципе не несёт основной его функции и при наличии минимальных знаний Lua может быть исключена.
    Минимальные знания мной были применены и я получил из этого кода то что может работать путем непосредственного запуска :) dofile
    Вопрос заключался в том как из в принципе работающего файла с кодом телнет сервера сделать опять модуль каким он и являлся до модификации, не требовалось вникать в суть самого кода сервера так как изначально я привел файл какой работает не в виде модуля.

    ПС: По моим вопросам можно понять что я сам тем более не програмист и подавно, и права обьективно рассуждать о том что и как сделал некий T Ellison в июне 2019 года в качестве нового модуля телнет сервера я лично не имею.
    Всё что я могу это взять плод его труда и попытаться както им воспользоваться, "еслиб не потраченное время авторов то учебники пришлось бы писать комуто другому."
     
  16. serg3295

    serg3295 Гуру

    Всё-таки изначально вопрос звучал так - "У меня есть вот эта длинная строка, и она некорректно загружает модуль".
    Я не знаю, что и как там делает этот minitelnet (как выяснилось, его код был изуродован злобным форматтером). Я просто посмотрел, что модуль возвращает таблицу, а не функцию, и предложил вариант вызова.

    @8bitai
    Однако, я не уверен, что мой вариант корректно использует socket в качестве параметра. Поэтому ваш вариант предпочтительнее. Вы просто забыли передать параметр в функцию, и модуль не получал сокет.
    То есть надо написать вот так:
    Код (C++):
    local tcpServer = net.createServer(180)
    tcpServer:listen(23, function(skt) require("minitelnet").telnetd(skt) end)
     
    Вынос созданного сервера в отдельную переменную даёт возможность его закрыть tcpServer:close(), если вдруг возникнет такое желание. Ну и улучшает читаемость кода. Но можно и в одну строку. Мне не жалко.

    Теперь про отладку. Если непонятно, что происходит, то можно было бы временно вынести require из параметров listen
    testCB = <что-то там с require>
    ...listen(23, testCB)

    и посмотреть что же оказывается в testCB.

    @ИгорьК
    Я тоже везде использую mqtt, но telnet иногда нужен в технологических целях.
     
    8bitai и ИгорьК нравится это.
  17. 8bitai

    8bitai Нерд

    мне телнет нужен как один из простых способов получения дистанционно и динамически изменяемого функционально - RIO (remote input/output) модуля, через какой ведётся управление другим/ми устройством/ами.
    Сама прошивка nodemcu разумеется не меняется , периодически меняется только текущий рабочий и довольно простой луа код по определённым генерируемым внешними средствами шаблонам.
     
  18. ИгорьК

    ИгорьК Гуру


    Когда я руководил юристами, то требовал для итоговых документов проводить "тест уборщицы": если документ понятен уборщице - это хороший документ. Юридический документ! Понятен уборщице! Невероятно?

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

    Этим правилом стараюсь руководствоваться и в других делах :)

    Сначала мои юристы горячились: "ну что тут не понятно". Но постепенно, насилие над их личностями перевело оных в плоскость: "а все ли я сделал так, чтобы было понятно каждому" :)
     
    8bitai нравится это.
  19. obuhanoe

    obuhanoe Гик

    Доброго всем дня.
    Приехал ко мне из Китая поплавковый датчик с герконом (https://aliexpress.ru/item/40002487...l.0.0.5c334aa6zFSUKM&sku_id=12000032242294794)

    В нижнем положении датчик выдает 1, в верхнем 0 - хочу его использовать в емкости для полива, чтобы не было перелива.

    Подключение: один конец от датчика к 3,3V, второй к пину ADC.

    Проверил с esp8266 (пин A0, который ADC), код ниже приведу - работает как надо - ложных срабатываний не наблюдал, переключения верные при перемещении попловка.
    Проверил с ESP32 - (проверил разные пины: 36,34,4 где присутствует ADC) - можем работать пару минут нормально потом, значение инвертируется (хотя геркон не передвигался) и больше не изменяется.
    Что мне кажется, я делаю не так - но пока не пойму что именно - натолкните на мысль, буду благодарен.
    Код (Lua):
    -- esp8266
    do
        gpio.mode(0, gpio.PULLUP)
        local start = function(_tmr)
       
           val = gpio.read(0)
           print(val)
        end

        tmr.create():alarm(1000*1.0, tmr.ALARM_AUTO, function(t) start(t) end)

    end
    Код (Lua):
    -- esp32
    do
        gpio.config({gpio=34, dir=gpio.IN, pull=gpio.PULL_UP})
        local start = function(_tmr)
       
           val = gpio.read(34)
           print(val)
        end

        tmr.create():alarm(1000*1.0, tmr.ALARM_AUTO, function(t) start(t) end

    end
    Подключил по схеме как тут указано для ардуины : https://vk-book.ru/datchik-urovnya-...gerkona-k-arduino/?ysclid=lj5onaepp5153124786
    Поэтому подключение элементарное: геркон не имеет полярности, поэтому все что нужно, это подключить одним электродом к 5V, а другим к любому цифровому или аналоговому пину. И не забыть притянуть геркон к земле через резистор номиналом от 10 кОм. Все то же самое, что и с обыкновенной кнопкой.

    Для ESP32 немного по другому: один конец к 3.3В, другой к 34 пину, и к GND через резистор 10кОм.
    Работать стало как надо.
     
    Последнее редактирование: 22 июн 2023
  20. ИгорьК

    ИгорьК Гуру

    Пин ADC (A0) измеряет напряжение на себе от 0 до 1 вольта (обычно на плате сделана схема, что не пускает к пину больше 1 вольта ESP8266), выдавая при этом цифирь от 0 до 1024. Как это может работать в принципе? Может, D0?

    Зачем вам АDС? ADC - (analog to digital converter) переводит аналоговые сигналы в цифровые. У вас здесь нет аналогового сигнала. Датчик надо подключить к VCC через резистор 10 ком. Вы подключили - стало работать. Так работают все цифровые ноги.

    к 3.3 вольтам. И только к цифровому пину, если это ESP8266. ESPЗ2 - к любому, но в режиме цифровом.
     
    Последнее редактирование: 22 июн 2023
    DetSimen нравится это.