ESP8266: BMP085, narodmon.ru... и другие бесполезные вещи.

Тема в разделе "Глядите, что я сделал", создана пользователем ИгорьК, 8 апр 2015.

  1. ИгорьК

    ИгорьК Гуру

    UPD: ESP-07 +BMP180, AM2302, DS18B20 С публикацией на narodmon.ru и сервер MQTT здесь.

    Возьмем модуль ESP8266 и bmp085 из набора Матрешка Альфа, соединим как показано на картинке, зальем что положено куда положено и получим на народном мониторинге показания датчика - температуру и давление.
    tteesstt.jpg
    Некоторые подробности. Соединять будем так:
    Connection.png
    А грузить будем следующие файлы:
    bmp085.lua
    Код (Lua):
        local moduleName = ...
        local M = {}
        _G[moduleName] = M
        local id=0
        local oss = 0
        local CO = {}
        local function read_reg(dev_addr, reg_addr)
          i2c.start(id)
          i2c.address(id, dev_addr ,i2c.TRANSMITTER)
          i2c.write(id,reg_addr)
          i2c.stop(id)
          i2c.start(id)
          i2c.address(id, dev_addr,i2c.RECEIVER)
          local c=i2c.read(id,1)
          i2c.stop(id)
          return c
        end
        local function write_reg(dev_addr, reg_addr, reg_val)
          i2c.start(id)
          i2c.address(id, dev_addr, i2c.TRANSMITTER)
          i2c.write(id, reg_addr)
          i2c.write(id, reg_val)
          i2c.stop(id)
        end
        local function getShort(reg_addr, signed)
          local tH = string.byte(read_reg(0x77, reg_addr))
          local tL = string.byte(read_reg(0x77, (reg_addr + 1)))
          local temp = tH*256 + tL
          if (temp > 32767) and (signed == true) then
            temp = temp - 65536
          end
          return temp
        end
        function M.init(d, l)
          if (d ~= nil) and (l ~= nil) and (d >= 0) and (d <= 11) and (l >= 0) and ( l <= 11) and (d ~= l) then
            sda = d
            scl = l
          else
            print("iic config failed!") return nil
          end
            i2c.setup(id, sda, scl, i2c.SLOW)
            CO.AC1 = getShort(0xAA, true)
            CO.AC2 = getShort(0xAC, true)
            CO.AC3 = getShort(0xAE, true)
            CO.AC4 = getShort(0xB0)
            CO.AC5 = getShort(0xB2)
            CO.AC6 = getShort(0xB4)
            CO.B1  = getShort(0xB6, true)
            CO.B2  = getShort(0xB8, true)
            CO.MB  = getShort(0xBA, true)
            CO.MC  = getShort(0xBC, true)
            CO.MD  = getShort(0xBE, true)
        end
        function M.getUT(num_10x)
          write_reg(0x77, 0xF4, 0x2E);
          tmr.delay(10000);
          local temp = getShort(0xF6)
          local X1 = (temp - CO.AC6) * CO.AC5 / 32768
          local X2 = CO.MC * 2048/(X1 + CO.MD)
          local r = (X2 + X1 + 8)/16
          if(num_10x == true) then
            return r
          else
            return ((r/10).."."..(r%10))
          end
        end
        function M.getUP_raw(oss)
          local os = 0
          if ((oss == 0) or (oss == 1) or (oss == 2) or (oss == 3)) and (oss ~= nil) then
            os = oss
          end
          local ov = os * 64
          write_reg(0x77, 0xF4, (0x34 + ov));
          tmr.delay(30000);
          local MSB = string.byte(read_reg(0x77, 0xF6))
          local LSB = string.byte(read_reg(0x77, 0xF7))
          local XLSB = string.byte(read_reg(0x77, 0xF8))
          local up_raw = (MSB*65536 + LSB *256 + XLSB)/2^(8 - os)
          return up_raw
        end
        function M.getUP(oss)
          local os = 0
          if ((oss == 0) or (oss == 1) or (oss == 2) or (oss == 3)) and (oss ~= nil) then
            os = oss
          end
          local raw = M.getUP_raw(os)
          local B5 = M.getUT(true) * 16 - 8;
          local B6 = B5 - 4000
          local X1 = CO.B2 * (B6 * B6 /4096)/2048
          local X2 = CO.AC2 * B6 / 2048
          local X3 = X1 + X2
          local B3 = ((CO.AC1*4 + X3)*2^os + 2)/4
          X1 = CO.AC3 * B6 /8192
          X2 = (CO.B1 * (B6 * B6 / 4096))/65536
          X3 = (X1 + X2 + 2)/4
          local B4 = CO.AC4 * (X3 + 32768) / 32768
          local B7 = (raw -B3) * (50000/2^os)
          local p = B7/B4 * 2
          X1 = (p/256)^2
          X1 = (X1 *3038)/65536
          X2 = (-7357 *p)/65536
          p = p +(X1 + X2 + 3791)/16
          return p
        end
        function M.getAL(oss)
          return (M.getUP(oss) - 101325)*843/10000
        end

        return M
     
    NarodMonPress01.lua:
    Код (Lua):
    function sendData()
    bmp085 = require("bmp085")
    bmp085.init(4,3)
        t=bmp085.getUT(true)/10
        t1=bmp085.getUP(oss)/100
        print("Temp:"..t.." C\n")
        print("Pressue:"..t1.."\n")
        local dataN = "#XX-XX-XX-XX-XX-XX\n" -- X Меняем на свои циферки
        dataN =dataN.."#Pressure#"..t1.."\n#Temperature#"..t.."\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')
        bmp085 = nil
        package.loaded["bmp085"]=nil
    end
    sendData()
    tmr.alarm(0, 600000, 1, function() sendData() end )
     
    И init.lua
    Код (Lua):
    do
    FileToExecute="NarodMonPress01.lc"
    l = file.list()
    for k,v in pairs(l) do
      if k == FileToExecute then
        print("*** You have got 20 sec to stop timer 0 ***")
        print("*******    Execute: tmr.stop(0)    *******")
        tmr.alarm(0, 20000, 0, function()
          print("Executing ".. FileToExecute)
          dofile(FileToExecute)
        end)
      end
    end
    end
     
    И... ничего у вас не получится. Потому что:
    - забыли поменять циферки на свои в файле NarodMonPress01.lua, и потому что
    - у вас вообще ничего не запускается - модуль пишет что не хватает памяти.
    Зачем это вообще нужно, как с этим справиться - в следующем посте.
     
    Последнее редактирование: 20 авг 2016
  2. Kopilov

    Kopilov Гик

    Это розыгрыш?
    Зная, что Вы любите "вуалировать" ссылки (а зачем?), я не ожидал подвоха, но ссылка на поисковую выдачу Яндекса в первом посте -- как-то слишком. А думал, Амперка новый набор выпустила.
     
  3. ИгорьК

    ИгорьК Гуру

    Это шутка. Не расстраивайтесь.
    Почти шутка. Амперка готовит много хороших вещей, я слышал.
    А что Вы имеете в виду "вуалировать ссылки"? Прикалывать ссылки к тексту, для его пояснения общая практика.
     
  4. Kopilov

    Kopilov Гик

    Не расстраиваюсь :) К тому же Вы, вроде, почти вошли в её коллектив!
    Имею ввиду, что по ссылке "чёрный ящик" http://goo.gl/O7PTfn вместо реальной цели http://yandex.ru/yandsearch?text=Матрешка Амперка. Сервисы укорачивания ссылок, безусловно, полезны, но вмеру. Можно использовать их при вставке длинной ссылки в plain-текст (например, e-mail без HTML или комментарий исходного кода) или в пост, не придумывая текста поверх. Можно сделать "пасхальное яйцо", как тут. А укорачивать URL ссылок, "приколотых" к осмысленному тексту (как в этой теме, например), -- ИМХО, плохой тон. Большинство посетителей хотели бы, наведясь на ссылку, узнать, куда она указывает. И ладно, если бы исходная ссылка была какой-нибудь бессмыслицей, а так теряется одна из изюминок этого форума: наличие названия темы в URL.
     
    ИгорьК нравится это.
  5. ИгорьК

    ИгорьК Гуру

    Нет, к коллективу Амперки я имею отношение лишь как лицо, позволяющее себе его критику, не более. Я работаю в компании ТехноНИКОЛЬ, это не тайна. Ну да я не один здесь, если считать коллективом всех наличествующих критиков :)
    Про ссылки я как-то не думал в таком разрезе. Более того, именно Амперка приучила меня к укорачивателю - поскольку Амперка формирует ссылки на свои посты кракозяблами, и очень длинными, их проще укорачивать. Попробуйте сформировать ссылку, например, на этот пост.
    А вообще, у меня много постов на этом форуме, наверно, это первая такая шутка :) Ну... или Амперка правда выпустит Матрешку Альфа :) Может я угадал :)
    http://forum.amperka.ru/threads/esp8266-bmp085-narodmon-ru-и-другие-бесполезные-вещи.4801/#post-38159 - это куда ведет?
    Хм..... а ведь правда, ссылка получилась в итоге осмысленной. Спасибо, учту!
    Надеюсь, в приведенном Вами примере моей темы все ссылки соответствуют логике моих сообщений.
     
    Последнее редактирование: 9 апр 2015
  6. Kopilov

    Kopilov Гик

    Это называется urlencode -- стандарт отображения кириллицы и спецсимволов в адресной строке. Типовой сервер воспринимает подобные символы только так, а браузер при возможности приводит их в "человеческий" формат.
     
  7. ИгорьК

    ИгорьК Гуру

    Продолжим. Итак, Вы заменили иксы на цифры в файле NarodMonPress01.lua, но все это не работает, и оповещает вас о нехватке памяти.
    Спасет нас замечательный автор замечательной программы ESPlorer, который выпустил ее новую версию. Новая версия позволяет очень удобно конвертировать файлы lua в бинарники lc. А именно:
    1. Загружаем файл bmp085.lua путем его открытия и нажатия на кнопку "Save to ESP".
    001.jpg
    2. Наблюдаем картину, а затем нажимаем на кнопку Reload. Под ней появляется кнопка bmp085.lua
    003.jpg
    Правой кнопкой мыши по ней:
    004.jpg
    Получаем:
    005.jpg
    Правой кнопкой мыши по кнопке bmp085.lua и удаляем этот файл. Получаем:
    006.jpg
    Также поступаем и с файлом NarodMonPress01.lua . Последним грузим файл init.lua - его можно не компилировать. В результате, устройство должно заработать и отправить информацию на народный мониторинг.
    007.jpg
     
  8. ИгорьК

    ИгорьК Гуру

    Некоторые пояснения.
    Не думаю, что найдется много желающих практически использовать этот проект, хотя он полностью рабочий и некоторое время трудится на сайте. Через неделю-другую я его выключу за ненадобностью.
    Он возник из победы чудес техники ESP8266 над злобной жабой жадности, а именно.
    Приобрел я в Амперке анемометр и прицепил его к действующему проекту. Рабочая плата, в силу специфики измерения температуры, находится рядом с котлом. Из нее удается измерять проводными датчиками три температуры - на улице, в системе отопления на выходе из котла и в домике. Но это расположение не дает возможности правильно установить анемометр , чтобы он был открыт всем ветрам, без намотки провода вокруг домика. Да его лучше вообще отнести подальше.
    Раньше это должно было решаться либо кошмаром двух NRF24l1+ (причем актуален вопрос прохождения сигнала через деревянные стены) и какой-то ардуиной, либо, вместо них, wifi шилдом, цена на который даже после снижения заставляет задуматься...
    А теперь - с применением ESP8266, который можно отнести вместе с анемометром подальше, да за одно прицепить к нему датчик давления из вышеописанного набора :) Чтобы ножки не простаивали. Потому что читать аналоговый вход модуля также просто, как и в Ардуиной - одной командой. За исключением... Смотрим картинку.
    0081.jpg
    Имеем рядом три модуля esp-1, esp-3, esp-201. Специально снял все вместе, чтобы были видны размеры, Для работы аналогового входа esp-1 без злобного железного хака- напайки провода на одну из ножек не годится. И для этого нужен соколиный глаз твердая рука.
    ESP-3 для такой работы вполне годится, как впрочем и ряд других вариантов этого модуля. Однако... Расстояние между ножками у них - 2 мм. То есть стандартные гребенки к ним не подходят. И только красавец ESP-201 имеет стандартную ширину пинов, а также дополнительные выводы земли и питания. За что поплатился размерами.
    Вот такой маленький обзор модулей для вашей информации.
    А работать это будет так. ESP8266 читает данные с анемометра и датчика давления, отправляет через wifi данные в таблицу mysql, что висит на Arduino Yun, которые последняя уже транслирует на народный мониторинг. В настоящее время так уже трудится один модуль ESP8266. Он передает Ардуинке информацию с двух датчиков ds18b20, расположенных в другом месте домика. И выглядит это так:
    011.png
    UPD 12/04/2015. Датчик переехал сюда http://narodmon.ru/1424# работает как и обещал выше.
     
    Последнее редактирование: 12 апр 2015
  9. xopkep

    xopkep Нуб

    А что делать если при попытке компилировать, сообщается 0 нехватка памяти?
     
    Последнее редактирование: 21 май 2015
  10. Apofiz

    Apofiz Гик

    А анемомертр у вас самодельный или готовый?
     
  11. ИгорьК

    ИгорьК Гуру

    То что я здесь публикую гарантированно работоспособно (по крайней мере компилируется, с логикой бывают, конечно, дырки :) ).
    А если в целом, то несколько вещей. Обновить прошивку и изо всех сил уменьшать код:
    - убирать из кода все print() и вообще все пробелы где это возможно не b = 0 a b=0;
    - отказаться от Си-шного (очень правильного подхода):
    Код (C):
    На С++:
    int myHomeLight = 0; // Эта переменная отражает состояние включения освещения
    print(myHomeLight);

    Lua:
    ml=0
    print(ml)
    - шире использовать анонимные функции;
    - пользоваться конструкциями типа:
    Код (Lua):
    local a=10
    ...
    a=nil
    collectgarbage()
    - использовать указанное выше для загрузки и выгрузки модулей. См пример кода здесь: http://forum.amperka.ru/threads/esp8266-raspberry-pi-2-openhab-азы-управления-умным-домом.5043/#post-40347 :
    Код (Lua):
    ds18b20=require('ds18b20')
    ds18b20.setup(4)
    addres={}
    addres=ds18b20.addrs()
    local t=ds18b20.read(addres[1])
    m:publish("/myhome/out/temperature001/state",t,0,0)
    print("Temp "..t.." published!")
    ds18b20=nil
    package.loaded["ds18b20"]=nil
    collectgarbage()
     
    Последнее редактирование: 12 янв 2016
    xopkep нравится это.
  12. ИгорьК

    ИгорьК Гуру

    Вот этот: http://amperka.ru/product/anemometer-kit
     
  13. xopkep

    xopkep Нуб

  14. ИгорьК

    ИгорьК Гуру

    Мужик, ну ты крут, а я - лох! Вся тема для твоего поста и создана была. :)
     
    Последнее редактирование: 12 янв 2016
  15. xopkep

    xopkep Нуб

    Простите, не специально ;)
    можно я почти по теме? Скомпилировался bmp085.lua в .lc, всё заработало.... добавил node.dsleep(60000) и всё. Модуль потерян для человечества. Просыпается модуль только один раз, потом признаков жизни не подает. Как это можно исправить?
    И как затереть lua-скрипты? При перепрошивке они не исчезают.
     
  16. ИгорьК

    ИгорьК Гуру

    Дабы оживить модуль после попытки отправить его в глубокий сон надо правильно соединить две ноги на нем. Соединяли?
     
  17. xopkep

    xopkep Нуб

    Да, на есп-01 запаяна 8 нога на ресет. на есп-07 - запаяна перемычка. Сон на Си отрабатывает нормально, а вот на nodemcu выходит фейл.
     
  18. ИгорьК

    ИгорьК Гуру

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

    Securbond Гуру

    ESP-07 +BMP180, AM2302, DS18B20
    С публикацией на narodmon.ru и сервер MQTT.


    Надеюсь Игорь будет не против, если я положу свой код здесь, может кому то пригодится.
    Имеем ESP-07. к нему подключены датчики
    BMP180 на (gpio2/pin4, gpio5/pin1),
    AM2302 на (gpio4/pin2),
    DS18B220 на (gpio14/pin5)
    Данные собираются в функции getSensor() и возвращаются из неё в глобальные переменные tBmp, pBmp, tAM, humiAM, tDS
    Потом эти данные публикуются на сервер MQTT, а затем на народный мониторинг.
    После этого модуль засыпает на 6 мин (что бы narodmon.ru не заблокировал)

    Использована прошивка собранная здесь - http://nodemcu-build.com/
    подключены модули - adc, bit, bmp085, dht, file, gpio, http, i2c, mqtt, net, node, ow, pwm, rtcmem, rtctime, sntp, spi, tmr, uart, wifi. Прошивка с плавающей точкой.
    Плюс к этому всему нужен скрипт lua для датчика DS18B20 (приложен к сообщению)
    Так же в коде не забыть указать мак адрес своей ESP для народного мониторинга и адрес брокера MQTT .


    Код (Javascript):
    pinAM = 2
    pinDS = 5
    sda = 1
    scl = 4
    Broker="192.168.0.100" --здесь код Вашего брокера !!!
    port=1883
    myClient="tempEsp2"
    iogin=""
    pass=""
    m = mqtt.Client( myClient, 120, login, pass)


    sleepdelay = 360 -- в секундах, сколько спать датчику между умываниями (10 минут.)
    killdelay = 20 -- в секундах, сколько времени устройство будет неуспешно
    -- пытаться передать информацию.

    function publish_data(tDS, tBmp, pBmp, tAM, humiAM)
                tmr.alarm(0, 2000, 0, function()
                m:publish("/pogoda/sensors/tempDS",tDS,0,0, function(conn)      
                print("TempDS "..tDS.." published!")
                end)
           
             tmr.alarm(1, 500, 0, function()
                m:publish("/pogoda/sensors/tempBMP",tBmp,0,0, function(conn)
                print("TempBMP "..tBmp.." published!")
                end)
             
             
              tmr.alarm(2, 500, 0, function()
                m:publish("/pogoda/sensors/presBMP",pBmp,0,0, function(conn)
                print("PresBMP "..pBmp.." published!")
                end)
               
                   
              tmr.alarm(3, 500, 0, function()
                m:publish("/pogoda/sensors/tempAM",tAM,0,0, function(conn)
                print("TempAM "..tAM.." published!")
                end)
             
               
              tmr.alarm(4, 500, 0, function()
                m:publish("/pogoda/sensors/humiAM",humiAM,0,0, function(conn)
                print("HumiAM "..humiAM.." published!")
                end)
             
             
               tmr.alarm(5, 500, 0, function()
                    local bat = (adc.readvdd33(0)/1000)
                    m:publish("/pogoda/sensors/presBMP/volt/state",bat,0,0, function(conn)
                    print("Bat "..bat.." published!")
                   end)                        
               
                    collectgarbage()
              disconnect()            
               end)
               end)
               end)
               end)
               end)
               end)
                                       
            end

                function sendNarod(tDS, tBmp, pBmp, tAM, humiAM)
           
                local bat = (adc.readvdd33(0)/1000)
                local dataN = "#XX-XX-XX-XX-XX-XX\n" -- поставить свои цифры
           
                dataN =dataN.."#T1#"..tDS.."\n"
                dataN =dataN.."#T2#"..tBmp.."\n"
                dataN =dataN.."#P1#"..pBmp.."\n"
                dataN =dataN.."#H1#"..humiAM.."\n"
                dataN =dataN.."#T3#"..tAM.."\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()
                   disconnect()
                   end)
                 
                 t = tmr.now()
                 conn:connect(8283,'narodmon.ru')
             
            end
    function run_main_prog()
        print("Main  program starts!")
     
        publish_data(tDS, tBmp, pBmp, tAM, humiAM)
        sendNarod(tDS, tBmp, pBmp, tAM, humiAM)
     
    end

    function getSensor()
    bmp085.init(sda, scl)
    tBmp = (bmp085.temperature()/10)
    pBmp = (bmp085.pressure()* 75 / 10000)

    status,tAM,humiAM = dht.readxx(pinAM)

    local ds18b20 = require('ds18b20')
      ds18b20.setup(pinDS)
      local addres={}
      addres=ds18b20.addrs()
      tDS = ds18b20.read(addres[1])

      adc.force_init_mode(adc.INIT_VDD33)
    return tBmp, pBmp, tAM, humiAM, tDS
    end

     
     


    function disconnect()
        tmr.alarm(3, 3000, 0, function()
            print("Sleep now!")
            node.dsleep(1000000*sleepdelay,0)
        end)
    end
    tmr.alarm(5, 1000*killdelay, 0, function() disconnect() end)
    getSensor() -- первый раз меряем температуру. Помним зачем? Отправлять будем второе измерение температуры
    tmr.alarm(0, 1000, 1, function()
         print("wifi.sta.status = "..wifi.sta.status())
         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)
            run_main_prog()
             end)
         end
    end)

    Ну и всё это благодаря статьям топикстартера - ИгоряК. Огромная ему за это благодарность.
     

    Вложения:

    Последнее редактирование: 20 авг 2016
    ИгорьК нравится это.
  20. ИгорьК

    ИгорьК Гуру

    Заголовочек придумайте, чтобы в начало темы было что вынести :)