ESP8266/NodeMCU Lua

Тема в разделе "Arduino & Shields", создана пользователем Securbond, 26 мар 2016.

  1. Securbond

    Securbond Гуру

    Не так давно пришёл мне вот такой модуль.
    image.jpeg
    Прошил его прошивкой отсюда - http://nodemcu-build.com/
    Распиновка данного модуля.
    image.jpeg
    Прошивку прошиваю всегда программой
    ESP8266Flasher - http://cxem.net/arduino/files/arduino175_nodemcu-flasher-master.rar

    Для всех остальных вещей использую программу
    ESPlorer - http://cxem.net/arduino/files/arduino175_ESPlorer.rar
    Прошивка с плавающей точкой, подключенные модули -
    Код (Java):
    modules: adc,bit,dht,file,gpio,mqtt,net,node,ow,rtcmem,rtctime,spi,tmr,uart,wifi
     
    Начинаю разбираться и буду выкладывать основные примеры скриптов для работы с данным модулем.
     
    Последнее редактирование: 28 мар 2016
    xp-lu нравится это.
  2. Securbond

    Securbond Гуру

    1. Не будем нарушать традиции и подключим два датчика
    DHT-11 и DHT-22.


    Описание тут - http://nodemcu.readthedocs.org/en/dev/en/modules/dht/
    Подключаем оба на один пин
    image.jpeg
    Пишем скрипт lua
    Код (Java):
    pin = 5
    status,temp,humi = dht.readxx(pin)
    status,temp2,humi2 = dht.read11(pin)
    if( status == dht.OK ) then
      print("DHT Temperature:"..temp..";".."  Humidity:"..humi)
      print("DHT Temperature:"..temp2..";".."    Humidity:"..humi2)
    elseif( status == dht.ERROR_CHECKSUM ) then
      print( "DHT Checksum error." );
    elseif( status == dht.ERROR_TIMEOUT ) then
      print( "DHT Time out." );
    end
    Заливаем, получаем -

    luaDHT.PNG
     
    Последнее редактирование: 26 мар 2016
    ИгорьК нравится это.
  3. noevile

    noevile Гик

    тоже хочу такую .. хочу хочу хочу .. надо заказать
     
  4. Securbond

    Securbond Гуру

    2. Подключим модуль DS3231 (часы реального времени)
    Из всех описаний что нашел, толком ни один не работал... Пришлось убить 4 часа жизни.
    image.jpeg
    - Основной скрипт (вроде библиотеки в Arduino IDE)
    Код (Java):

    function decToBcd(val)
        local d = string.format("%d",tonumber(val / 10))
        local d1 = tonumber(d*10)
        local d2 = val - d1
       return tonumber(d*16+d2)
    end
    function bcdToDec(val)
          local hl=bit.rshift(val, 4)
          local hh=bit.band(val,0xf)
         local hr = string.format("%d%d", hl, hh)
         return string.format("%d%d", hl, hh)
    end
    sda = 1 -- Устанавливаем пин SDA D3 на плате -  пин 1
    scl = 2 -- Устанавливаем пин SCL D3 на плате -  пин 2
    address = 0x68
    id=0
    i2c.setup(id, sda, scl, i2c.SLOW)


    readTime = function ()
       wkd = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" }
       i2c.start(id)
       i2c.address(id, address, i2c.TRANSMITTER)
       i2c.write(id, 0x00)
       i2c.stop(id)
       i2c.start(id)
       i2c.address(id, address, i2c.RECEIVER)
       c=i2c.read(id, 7)
       i2c.stop(id)
       return  bcdToDec(string.byte(c,1)),
             bcdToDec(string.byte(c,2)),
             bcdToDec(string.byte(c,3)),
             wkd[tonumber(bcdToDec(string.byte(c,4)))],
             bcdToDec(string.byte(c,5)),
             bcdToDec(string.byte(c,6)),
             bcdToDec(string.byte(c,7))
    end

    setTime = function (second, minute, hour, day, date, month, year)
       i2c.start(id)
       i2c.address(id, address, i2c.TRANSMITTER)
       i2c.write(id, 0x00)
       i2c.write(id, decToBcd(second))
       i2c.write(id, decToBcd(minute))
       i2c.write(id, decToBcd(hour))
       i2c.write(id, decToBcd(day))
       i2c.write(id, decToBcd(date))
       i2c.write(id, decToBcd(month))
       i2c.write(id, decToBcd(year))
       i2c.stop(id)
    end
    - Обзываем его ds3231.lua и заливаем в наш ESP.
    - Теперь напишем маленький скрипт записи времени в чистый модуль DS3231 (ведь изначально там пусто)
    Код (Java):
    require('ds3231')
    setTime  (3, 17, 21, 7, 26, 03, 16)
    Где - setTime (секунды, минуты, часы, день недели, число, месяц, год)
    Нужно поймать момент что бы часики шли как можно точнее.
    - Теперь получим то к чему так долго стремились, а именно наше время. Для этого еще один маленький скрипт.
    Код (Java):
    require('ds3231')

    s, m, h, d, dt, mn, y = readTime()

    print(string.format("Time & Date: %s:%s:%s %s/%s/%s day:%s",
        h, m, s, dt, mn, y, d))
    Результат -

    luaTIME.PNG

    ВСЁ !!!
    P/S: Забыл сказать, что часы подключаются по шине I2C, по этому пришлось перепрошить модуль так как моя первая прошивка была собрана без этой функции.
     
    Последнее редактирование: 26 мар 2016
    alp69 и ИгорьК нравится это.
  5. ИгорьК

    ИгорьК Гуру

    А как же Ардуино IDE? Это же предательство идеалов! :)
    Где тонна кода? Почему так мало кода???? :)
     
  6. Securbond

    Securbond Гуру

    Честно скажу, что многие вещи на ardIDE сделал бы гораздо быстрее.. а тут как будь то работаешь без библиотек (вообще так и есть:D). Сложно, но для собственного развития и расширения кругозора очень полезно. Вот сел и решил прикрутить LCD I2C . если получится, конечно же выложу результат здесь.
     
  7. Securbond

    Securbond Гуру

    3. Подключим экран LCD I2c 16x2
    Пример кода взял тут - https://github.com/dvv/nodemcu-thingies/blob/master/lcd1602.lua
    Итак, берем код из примера и создаём скрипт с названием lcd1602.lua
    Код (C++):
    -- Example:
    -- i2c.setup(0, 3, 4, i2c.SLOW)
    -- lcd = dofile("lcd1602.lua")()
    -- lcd.put(lcd.locate(0, 5), "Hello, dvv!")
    -- function notice() print(node.heap()); lcd.run(0, "It's time! Skushai tvorojok!", 150, 1, notice) end; notice()
    ------------------------------------------------------------------------------
    local M
    do
      -- const
      local ADR = 0x27
      -- cache
      local i2c, tmr, delay, ipairs, type, bit, bor, band, bshl =
            i2c, tmr, tmr.delay, ipairs, type, bit, bit.bor, bit.band, bit.lshift
      -- helpers
      local _ctl = 0x08
      local w = function(b, mode)
        i2c.start(0)
        i2c.address(0, ADR, i2c.TRANSMITTER)
        local bh = band(b, 0xF0) + _ctl + mode
        local bl = bshl(band(b, 0x0F), 4) + _ctl + mode
        i2c.write(0, bh + 4, bh, bl + 4, bl)
        i2c.stop(0)
      end
      -- backlight on/off
      local light = function(on)
        _ctl = on and 0x08 or 0x00
        w(0x00, 0)
      end
      local clear = function()
        w(0x01, 0)
      end
      -- return command to set cursor at row/col
      --local _offsets = { [0] = 0x80, 0xC0, 0x94, 0xD4 } -- 20x4
      local _offsets = { [0] = 0x80, 0xC0, 0x90, 0xD0 } -- 16x4
      local locate = function(row, col)
        return (col + _offsets[row])
      end
      local define_char = function(index, bytes)
        w(0x40 + 8 * band(index, 0x07), 0)
        for i = 1, #bytes do w(bytes[i], 1) end
      end
      -- write to lcd
      local put = function(...)
        for _, x in ipairs({...}) do
          -- number?
          if type(x) == "number" then
            -- direct command
            w(x, 0)
          -- string?
          elseif type(x) == "string" then
            -- treat as data
            for i = 1, #x do w(x:byte(i), 1) end
          end
          delay(800)
        end
      end
      -- show a running string s at row. shift delay is _delay using timer,
      --     on completion spawn callback
      local run = function(row, s, _delay, timer, callback)
        _delay = _delay or 40
        tmr.stop(timer)
        local i = 16
        local runner = function()
          -- TODO: optimize calculus?
          put(
              locate(row, i >= 0 and i or 0),
              (i >= 0 and s:sub(1, 16 - i) or s:sub(1 - i, 16 - i)),
              " "
            )
          if i == -#s then
            if type(callback) == "function" then
              tmr.stop(timer)
              callback()
            else
              i = 16
            end
          else
            i = i - 1
          end
        end
        tmr.alarm(timer, _delay, 1, runner)
      end
      -- start lcd
      local init = function(adr)
        ADR = adr or 0x27
        w(0x33, 0)
        w(0x32, 0)
        w(0x28, 0)
        w(0x0C, 0)
        w(0x06, 0)
        w(0x01, 0)
        w(0x02, 0)
        -- expose
        return {
          define_char = define_char,
          light = light,
          clear = clear,
          locate = locate,
          put = put,
          run = run,
        }
      end
      -- expose constructor
      M = init
    end
    return M
     
    В коде пришлось добавить пару скобок, что бы работало.
    теперь, что бы вывести на экран надпись сделаем скрипт с простейшим примером
    Код (Java):
    i2c.setup(0, 1, 2, i2c.SLOW) -- тут 0 это ID 1 - пин(D3) SCL 2- пин(D4) SDA
    lcd = dofile("lcd1602.lua")()
    lcd.put(lcd.locate(0, 5), "Privet") -- Пишем в первой строке с 5 символа слово -Привет
    --lcd.put(lcd.locate(1, 3), "Amperka.ru") - если нужно во второй строке написать что то

    function notice()
    lcd.run(1, "Amperka.ru", 200, 1, notice) end; notice() -- эта строка будет динамически передвигаться по экрану
    Наслаждаемся полученным результатом.
    image.jpeg
     
    Последнее редактирование: 28 мар 2016
    alp69 и ИгорьК нравится это.
  8. alp69

    alp69 Форумчанин

    Попробовал повторить на NodeMCU V3. Не пошло. Загораются две строки полными знакоместами. Текст не выводится.
     
  9. Securbond

    Securbond Гуру

    Странно... может в прошивке Node MCU что то изменилось. Или экраны как то отличаются. Если найду такой экран, попробую еще раз.
     
  10. Securbond

    Securbond Гуру

    Все работает
    IMG_2313.JPG

    У Вас должно быть два файла.
    1. lcd1602.lua - в него закидываете то, что под спойлером
    2. И во втором файле можно оставить только первые три строчки для проверки
    И проверьте яркость и контрастность дисплея, бывает из за слабого контраста текста просто не видно.
     
    alp69 нравится это.
  11. alp69

    alp69 Форумчанин

    Спасибо за фотку :D
    Все заработало. Будь проклят тот день, когда я сел за баранку этого пылесоса стал пользоваться китайскими беспаечными макетками! :D:D:D
     
    Securbond нравится это.
  12. Securbond

    Securbond Гуру

    4. Подключение туевой хучи разных датчиков к NodeMCU.
    Отправка всего этого добра на narodmon.ru, в MQTT и вывод значений датчика на Oled I2C 128x32.

    Использованы датчики ds18b20, am2301 и AM2320 (BMЕ-280 ещё в пути:confused:)
    Основные куски кода (практически все) в скрипте взяты конечно же у ИгоряК. Мне такое в жизни не нацарапать. Оставляю здесь, что бы самому не потерять. Может кому ещё пригодится.
    Если кто то посоветует оптимизацию кода, и укажет на недочёты или ошибки буду признателен.
    Собираем прошивку тут - https://nodemcu-build.com
    необходимые модули
    Код (Text):
    modules: adc,am2320,bit,bme280,dht,file,gpio,i2c,mqtt,net,node,ow,pwm,rtctime,sjson,sntp,spi,tmr,u8g,uart,websocket,wifi,tls
     
    Неоходимые файлики в архиве.

    Основной скрипт WS1.lua с коментариями
    Код (Javascript):
    pinAM = 6
    pinDS = 3
    pinLED = 8 --светик будет моргать при успешной отправки даных в MQTT
    sda = 1 -- SDA Pin
    scl = 2 -- SCL Pin
    gpio.mode(pinLED,gpio.OUTPUT)
    gpio.write(pinLED,gpio.LOW)

    am2320.init(sda, scl) --инициализация датчика AM2320

    Broker="192.168.0.106" --адрес Вашего брокера !!!
    port=1883
    myClient="WS1"
    login=""
    pass=""

    --------Функция нициализации дисплея------------
    function init_OLED(sda,scl) --Set up the u8glib lib
         sla = 0x3C
         i2c.setup(0, sda, scl, i2c.SLOW)
         disp = u8g.ssd1306_128x32_i2c(sla,1)
         disp:setFont(u8g.font_10x20)
         disp:setFontRefHeightExtendedText()
         disp:setDefaultForegroundColor()
         disp:setFontPosTop()
         --disp:setRot180()     -- Rotate Display if needed
    end
    --------Функция вывода данных на экран дисплея--------
    function print_OLED()
       disp:firstPage()
       repeat
         disp:drawStr(5, 2, str1)
         disp:drawStr(5, 17, str2)
       until disp:nextPage() == false
    end

    -------Проверка подключения к серверу MQTT------------
    m = mqtt.Client( myClient, 120, login, pass)
    m:lwt("/pogoda/sensors/", "By!", 0, 0)
    m:on("offline", function(con)
      print ("Mqtt Reconnecting.")
      tmr.stop(2)
      tmr.alarm(1, 60000, 1, function()
      print ("Try Reconnecting...")
      m:connect(Broker, port, 0, function(conn)
      print("Mqtt Connected to "..Broker)
      tmr.stop(1)
      tmr.start(2)
      end)
    end)
    end)

    ----- Функция тправки данных на народный мониторинг----
    function sendNarod(t2320, h2320, tAM, humiAM, tDS)
                local bat = (adc.readvdd33(0)/1000)
                local dataN = "#18-FE-35-D6-3C-1A\n" -- поставить свои цифры
                dataN =dataN.."#T1#"..tDS.."\n"
                dataN =dataN.."#T2#"..tAM.."\n"
                dataN =dataN.."#T3#"..t2320.."\n"
                dataN =dataN.."#H1#"..humiAM.."\n"
                dataN =dataN.."#H2#"..h2320.."\n"
                dataN =dataN.."#U1#"..bat.."\n"
                dataN = dataN.."##\n"
                print(dataN)
                conn=net.createConnection(net.TCP, 0)
                conn:on("connection",function(conn, payload)
                    conn:send(dataN)
                    end)
                 conn:on("receive", function(conn, payload)
                   print('\nRetrieved in '..((tmr.now()-t)/1000)..' milliseconds.')
                   print('Narodmon says '..payload)
                   conn:close()      
                   end)
                 t = tmr.now()
                 conn:connect(8283,'narodmon.ru')
            end

    ---------Основная функция программы-------
    function RunMyProg()
    print("Main  program starts!")
    tmr.alarm(2, 5000, 1, function() --Публикуем данные каждые 5 сек
    gpio.write(pinLED,gpio.HIGH)
    publish_data()
    ---------
    init_OLED(1,2) -- подключаем дисплей
    print_OLED()   -- выводим данные на дисплей
    end)
    ---------Передача данных на narodmon.ru-----
    tmr.alarm(4, 360000, 1, function()
    sendNarod(t2320, h2320, tAM, humiAM, tDS)
    end)
    end

    ------Получение данных от датчиков--------
    function getSensor()
    tmr.alarm(3, 1000, 1, function()
    status,tAM,humiAM = dht.readxx(pinAM)
    local ds18b20 = require('ds18b20')
      ds18b20.setup(pinDS)
      local addres={}
      addres=ds18b20.addrs()
      tDS = ds18b20.read(addres[1])
      rh, t = am2320.read()
      t2320 = t/10
      h2320 = rh/10
      str1=(string.format("t:  %s C", t2320)) --переводим числовые параметры в строковые
      str2=(string.format("Hum:%s%%", h2320))

      return str1, str2, t2320, h2320, tAM, humiAM, tDS --возвращаем данные в глобальные переменные
    end)
    --print(string.format("RH: %s%%", rh / 10))
    --print(string.format("Temperature: %s degrees C", t / 10))
    end

    --------Публикация данных на сервер MQTT-----
    function publish_data()
                m:publish("/pogoda/sensors/tempDS",tDS,0,0, function(conn)       end)
               -- print("TempDS "..tDS.." published!")
                  m:publish("/pogoda/sensors/tempAM",tAM,0,0, function(conn)     end)
             --   print("TempAM "..tAM.." published!")
                 m:publish("/pogoda/sensors/humiAM",humiAM,0,0, function(conn)   end)
             --   print("HumiAM "..humiAM.." published!")
                 m:publish("/pogoda/sensors/t2320",t2320,0,0, function(conn)   end)
            --    print("t2320 "..t2320.." published!")
                 m:publish("/pogoda/sensors/h2320",h2320,0,0, function(conn)   end)
             --   print("h2320 "..h2320.." published!")
                local bat = (adc.readvdd33(0)/1000)
                 m:publish("/pogoda/sensors/volt/state",bat,0,0, function(conn)   end)
             --   print("Bat "..bat.." published!")
                  print("MQTT published!")
                 collectgarbage()
               gpio.write(pinLED,gpio.LOW)
               end                      

    ---START----

    getSensor()

    tmr.alarm(0, 3000, 1, function() -- проверяем WiFi каждые 3 сек
      if wifi.sta.status() == 5 and wifi.sta.getip() ~= nil then
      tmr.stop(0)
      m:connect(Broker, port, 0, function(conn)
      print("Mqtt Connected to: " .. Broker)
      RunMyProg()
      end)
      end
    end)

    IMG_2128.JPG

    Скрипт 100% рабочий. конфигурацию экрана OLED и необходимые шрифты можно выбрать при сборке прошивки.
     

    Вложения:

    • WStation.zip
      Размер файла:
      4,1 КБ
      Просмотров:
      592
    Последнее редактирование: 6 июл 2017
    ИгорьК нравится это.
  13. ИгорьК

    ИгорьК Гуру

    Какой дисплей? Ссылочкой поделитесь.
     
  14. Securbond

    Securbond Гуру

    Этот - Смотри, что нашлось на AliExpress http://s.aliexpress.com/IJRjiqIr
    Очень маленький. Разумнее взять 128х64
    Смотри, что нашлось на AliExpress http://s.aliexpress.com/yy2MZ7VJ
    Модуль u8g так же позволяет подключать похожие дисплеи на SPI шине. (Указывается при создании прошивки)
     
    ИгорьК нравится это.
  15. ИгорьК

    ИгорьК Гуру

    А они поддерживают хотя бы английские буковки?
     
  16. Securbond

    Securbond Гуру

    Попробуйте собрать прошивку с модулем u8g, при сборке на выбор куча шрифтов и много английских буковок)).
     
    ИгорьК нравится это.
  17. Securbond

    Securbond Гуру

    pruf:
    font1.JPG font2.JPG
     
  18. Насколько я понял это синяя платка устаревшая версия - WEMOS D1(retired)
    Черные WEMOS D1 R2 - поновее
    распиновки отличаются - может в этом проблема
    у этой синей такая распиновка
    D5 – sck builtin led
    D9 – wi-f- buildin led inversed

    D11 – D7
    D12 – D6
    D13 – D5
    D14 – D4
    D15 – D3
     
  19. Securbond

    Securbond Гуру

    В последнем посте речь идет о другой плате, впрочем это видно на фото. пины на ней чётко совпадают пины указанные в скрипте, с теми, что написаны на самой плате.
     
  20. Securbond

    Securbond Гуру

    И посмотрите внимательно на фото синей платы.. там пины подписаны дважды и один из вариантов совпадает с тем, что вы написали.