Arduino, ESP8266 Lua, Raspberry Pi 2 && OpenHab. Умный дом: азы управления.

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

  1. tammat

    tammat Нерд

    Спасибо, ;)
    Замылился глаз...
    И еще
    /* не работает
    var Or_Dir = transform("JSONPATH", "$live.wind_direction", live)

    logInfo("Mqtt_Json", "Wind Di Oregon = " + Or_dir)
    //postUpdate(OS_Dir, Or_Dir)
    */
    JSON
    { status: 200,
    process_time: 30.931949615478516,
    live:
    { wind_speed: 0,
    rainfall: 0,
    temperature: 14.2,
    low_battery: {},
    wind_direction: 'ESE',
    uv: '--',
    wind_angle: 112,
    forecast: 1,
    pressure: 992,
    local_time: '2016-05-17 12:56:40.884329',
    sealevel_pressure: 1008.4639999999999,
    humidity: 71,
    wind_gust: 0 } }
    Не хочет писать в string
     
  2. ИгорьК

    ИгорьК Гуру

    Не сталкивался пока с этой возможностью OpenHab..
     
  3. az3749

    az3749 Нерд

    У меня тоже такое было. В качестве датчика использовал внутренний термометр AtMega. Брокер тот же. Платформа EasyIot. Думаю по причине отсутствия пароля - хакеры шалят. Термометр я раньше проверял с сервисом narodmon. На 2000 отсчетов глюков термометра отмечено не было.
     
  4. ИгорьК

    ИгорьК Гуру

    Это было "мало тока" :) Всего то. Уже и забыл об этом.
    emper004.JPG
    emper005.JPG
     
    Последнее редактирование: 17 май 2016
  5. az3749

    az3749 Нерд

    У меня с током все впорядке. наблюдаются штыри в EasyIot величиной 70
    upload_2016-5-17_15-27-46.png
    У меня параллельно работал mqtt-spy. В нем штырей нет.
    upload_2016-5-17_15-31-40.png
    EasyIot похоже очень сырой. Возможно сделаю свое дубовое на paho. Сначало попробую OpenHub.
     
  6. ИгорьК

    ИгорьК Гуру

    31. IskraJS, ESP8266, nooLite MR1132, nooLite MT1132.
    Из подручных материалов собрал рабочую железку Iskra JS, nooLite MR1132, nooLite MT1132:
    0002.jpg 0001.jpg
    Модуль nooMT отсюда.
    Соединения таковы:
    [​IMG]
    А код таков:
    Код (Javascript):

    E.on('init', function() {

    // nooLiteAll0051.js
    // works

    /* Объект nooMT для передачи на Serial2 nooLite MT1132
    *
    *  Serial6 - приемник nooLite MR1132
    *  Serial3 - ESP8266
    */


    var nooMT = require('nooMT').connect(2);
    Serial6.setup(9600);
    Serial3.setup(9600);

    /*
    * Две переменные для обработки
    * событий в Serial портах
    */


    var cmd="";
    var command = "";

    Serial6.on('data', function (data) {
      //print(data.charCodeAt(0));
      cmd+=data;

      if(cmd == "OK\r\n") {
        print("Got OK!");
        cmd = "";
      }
      var idx = cmd.indexOf("\xAA");
      while (idx>=0) {
        // print("cmd.length = "+cmd.length);
        sendTo(cmd);
        cmd = "";
        idx = cmd.indexOf("\xAA");
      }
    });

    // Отправка данных о командах и информации nooLite
    var sendTo = function(mydata) {
      print("\nGot Data!");
      var message = [];
      var counter = 0;
      var summ = 0;
      while (counter < 11) {
        message[counter] = mydata.charCodeAt(counter);
        // print("message["+counter+"] = "+message[counter]);
        if(counter < 9) {
          summ = summ + message[counter];
          // print("summ = "+summ);
        }
        counter++;
      }
      summ = summ & 0xFF;
      // print("summ & 0xFF = "+summ);
      if(message[9] == summ+1){
        print("Summ is Good. Publishing Data!");
        if (message[3] != 21) {
            //serialESP.write(""+message[2]+":"+message[3]+"\n");
            Serial3.write(""+message[2]+":"+message[3]+"\n");
            print("From item "+message[2]+ " got message "+message[3]);
            if (message[3] === 15) {
              print("Stop Binding Now!");
              //serialNooMR.write("bind_mode_off\003\n");
              Serial6.write("bind_mode_off\003\n");
          }
        }
        else {
            var byteHigh = message[6];
            var byteLow  = message[5];
            byteHigh = byteHigh & 0x0F;
            byteHigh = byteHigh << 8;
            var temptemp = byteHigh + byteLow;
            if (temptemp > 0x7ff) {
              temptemp = temptemp - 0x1000;
            }
            temptemp = temptemp * 0.1;
            print("From item " +message[2] + " got temperture "+temptemp);
            Serial3.write(""+message[2]+":"+temptemp+"\n");
            if(message[7] !== 0) {
              print("From item " +message[2] + " got humi "+message[7]+"%");
              Serial3.write("10"+message[2]+":"+message[7]+"\n");
            }
        }
      }
    };

    // Прием команд, пришедших из ESP8266
    var inByte = "";
    Serial3.on('data', function(data) {
      inByte = data;
      print("InByte = "+inByte+" And Char Code is: "+inByte.charCodeAt(0));
      if  (inByte.charCodeAt(0) !== 10 && inByte.charCodeAt(0) !== 13) {
        command += inByte;
      }
      if(inByte.charCodeAt(0) == 0x0A || inByte.charCodeAt(0) == 0x0D)  {
        if(inByte.charCodeAt(0) == 0x0A) {
          print("Command = "+command);
          comToNoo(command);
          command = "";
        }
      }
    });

    // Команды на модуль MR1132
    var comToNoo = function(messToNoo){
      var sendto = "";
      var indOfDiv = messToNoo.indexOf(":");
      var top = messToNoo.substring(0,indOfDiv);
      var data = messToNoo.substring(indOfDiv+1);
      print("top is "+top+" && data is "+data);
      if      (top == "91") {sendto = sendto+"clear_all_cell";}
      else if (top == "92") {sendto = sendto+"clear_one_cell_"+data;}
      else if (top == "93") {sendto = sendto+"bind_mode_cell_"+data;}
      else if (top == "94") {sendto = sendto+"bind_mode_off";}
      else {
        nooMT.sendNooMT(parseInt(top, 10),parseInt(data, 10));
        return;
      }
      sendto = sendto+"\003\n";
      print(sendto);
      Serial6.write(sendto);
    };

    // Запуск скрипта на ESP8266
    setTimeout(function() {
      Serial3.write('dofile("UARTEspruino001003.lc")\n');
      setTimeout(function(){
        command = "";
        print('Command Set at "" By Timer');
      },5000);
    }, 5000);

    // Обнуление буфера команд от ESP8266
    setInterval(function(){
        if(Serial3.available() === 0) {
        command = "";
         // print('Command Set at "" By Serial');
      }
    }, 5000);
    });
     
    Скрипт на ESP8266 имеет название UARTEspruino001003.lc:
    Код (Lua):
    Broker="ВАШ_БРОКЕР"
    port=ВАШ_ПОРТ
    myClient="nooLite"
    name=myClient
    pass="ВАШ_ПАРОЛЬ"
    publish = false

    m = mqtt.Client(myClient, 180, name, pass)
    m:lwt("/lwt", myClient, 0, 0)

    m:on("offline", function(con)
        publish = false
        m:connect(Broker, port, 0, 0,
            function(conn)
                publish = true
                tmr.stop(1)
                m:subscribe(myClient.."/#",0, function(conn)
                 end)
        end)
        tmr.alarm(1, 90000, 1, function()
                  m:connect(Broker, port, 0, function(conn)
                    publish = true
                    tmr.stop(1)
                    m:subscribe(myClient.."/#",0, function(conn)
                    end)
               end)
         end)
        collectgarbage()
    end)

    uart.on("data","\n",
        function(input)
            if wifi.sta.status() == 5 then
                local topic
                local info
                topic, info = string.match(input, "(%d+):(%d+%.?%d?%d?)")
                if topic ~= nil  then
                  m:publish(myClient.."/"..topic.."/state",info,0,0)
                end
                topic = nil
                info = nil
                collectgarbage()
            end
      end, 0)
    m:on("message", function(conn, topic, data)
        if (string.find(topic, "state")) == nil then
            local top = string.gsub(topic, myClient.."/","")
            print(top..":"..data)
        end
        collectgarbage()
    end)

    tmr.alarm(0, 1000, 1, function()
        if wifi.sta.status() == 5 and wifi.sta.getip() ~= nil then
            tmr.stop(0)
              m:connect(Broker, port, 0, function(conn)
                    print("Connected.")
                    publish = true
                  m:subscribe(myClient.."/#",0, function(conn)
                    print ("Subscribed.")
                  end)
            end)
        end
    end)
     
     
    Последнее редактирование: 31 май 2016
  7. ИгорьК

    ИгорьК Гуру

    32. DS18b20 + ESP8266 на батарейках. Вариант 2.
    Вот здесь топик о первом варианте устройства. Опыт показал, что от двух батареек АА оно работает чуть больше месяца, при том, что отправляет температуру и напряжение батарейки каждые 10 минут.
    Вот как это выглядит про батарейку:
    bat.jpg
    Предлагаю опробовать другой вариант. Идея подсмотрена у nooLite, а именно:
    • проверка осуществляется каждые 10 минут;
    • запоминаются данные об измеренной температуре и количестве измерений;
    • если температура не отличается от предыдущей более чем на 0,5 градусов - данные не передаются;
    • количество измерений увеличивается на один;
    • если прошло определенное количество измерений, а данные не изменились - данные передаются все равно. Например, после 12 измерений каждое через 10 минут - раз в два часа данные все равно передаются;
    • соединение с Интернет (самая энергозатратная операция) происходит только после измерений и исключительно для передачи информации.
    • контролируется уровень заряда батареи. Выше установленной информация не передается.
    UPD. Еще один вариант кода здесь.
    Код Lua:
    Код (Lua):
    pin = 4 -- на этой ноге датчик

    ap = "ТОЧКА_ДОСТУПА"
    appass = "ПАРОЛЬ_К_ТОЧКЕ_ДОСТУПА"

    Broker="ВАШ_БРОКЕР"
    port=ПОРТ_БРОКЕРА
    myClient="tempMuvSleep02"
    iogin=myClient
    pass="pass"
    m = mqtt.Client( myClient, 120, login, pass)

    sleepdelay = 600 -- каждое измерение 600 секунд = 10 минут
    killdelay = 25 -- на всю операцию 25 секунд: есть связь, нет - в сон
    batcontrol = 2.8 -- вольтаж батареи, ниже которого передается информация о ней.
    countsleep = 12 -- принудительная передача данных через 12 измерений

    function pubdata(tmpr)
        print("PubData!")
        wifi.setmode(wifi.STATION)
        wifi.sta.config(ap , appass)
        wifi.sta.autoconnect(0)
        tmr.alarm(0, 1000, 1, function()
            if wifi.sta.status() == 5 and wifi.sta.getip() ~= nil then
                print("Got wi-fi!")
                tmr.stop(0)
                m:connect(Broker, port, 0, function(conn)
                    m:publish("/myhome/"..myClient.."/state",tmpr,0,0, function(conn)
                        print("Publised ".. tmpr)
                        tmr.alarm(1, 500, 0, function()
                        local bat = adc.readvdd33()
                        print("bat = "..bat)
                        if bat < (batcontrol*1000) then
                            bat = bat / 1000
                            m:publish("/myhome/"..myClient.."/bat",bat,0,0, function(conn)
                                disconnect()
                            end)
                        else
                            disconnect()
                        end
                        end)
                    end)
                end)
            end
        end)
    end



    function publish_data()
        print("work now!")
        local t = 85
        t = getTemp()
        print("Got "..t)
        if t ~= 85 then
            local oldt = rtcmem.read32(0)
            local count = rtcmem.read32(1)
            if (count + 1) < 1 then
                rtcmem.write32(1, 0)
            else
                rtcmem.write32(1, (count+1))
            end
            rtcmem.write32(1, (count+1))
            print("oldt "..oldt)
            local delta = t - oldt
            if delta < 0 then
                delta = delta * -1
            end
            print("Delta "..delta)
            print("count = "..count)
            if (delta > 8) or (count > countsleep) then
                rtcmem.write32(0, t)
                print("countsleep = "..count)
                rtcmem.write32(1, 0)
                if bit.isset(t, 15) then t = 1 - bit.bxor(t, 0xffff) end
                t = t * 625 / 10000
                print("t = "..t)
                print("Pubish Data!")
                pubdata(t)
            else
                print("Not changes. Go...")
                disconnect()
            end
        end
    end

    function getTemp()
        print("get t")
        local t = 85
        local ds18b20 = require('ds18b20')
        ds18b20.setup(pin)
        local addres={}
        addres=ds18b20.addrs()
        if addres[1] ~= nil then
            t = ds18b20.read(addres[1])
        end
        print("Got "..t)
        return t
    end

    function disconnect()
        tmr.alarm(3, 500, 0, function()
            print("Sleep Now!")
            node.dsleep(1000000*sleepdelay, 4)
        end)
    end
    tmr.alarm(5, 1000*killdelay, 0, function()
        print("Get Sleeped By Timer")
        disconnect()
    end)

    publish_data()
     
    • Ясный пень, все что есть print(...) - удалить. После того как увидите что все работает и как это происходит.
    • Чтобы работал режим сна - нужен паяльник. Смотреть предыдущий пост о датчике на батарейках.
    • Файл ds18b20.lua - прилагается. Он не стандартный, а несколько усеченный.
    • Прошивка nodemcu прилагается.
    А вот и датчик в теплицу:
    20160612_200100.jpg 20160612_213353.jpg
     

    Вложения:

    • nodemcu.zip
      Размер файла:
      311 КБ
      Просмотров:
      563
    • ds18b20.zip
      Размер файла:
      765 байт
      Просмотров:
      516
    Последнее редактирование: 14 июн 2016
    alp69 нравится это.
  8. alp69

    alp69 Форумчанин

    Обновление шапки будет?
     
  9. ИгорьК

    ИгорьК Гуру

    Обновлено уже.
     
  10. alp69

    alp69 Форумчанин

    Сваял код для управления двумя мощными нагрузками. С обратной связью для контроля. Железо без силовой части пока на макете. Работает. Выкладывать сейчас? Или подождете до реализации "под ключ" и прогона на объекте?
     
  11. alp69

    alp69 Форумчанин

    Упс... Сижу с телефона - не прокрутил до следующего поста.
    Спасибо!
     
  12. ИгорьК

    ИгорьК Гуру

    Дело хозяйское: уверены - выкладывайте. Заголовок шрифт SIZE=6.
     
  13. alp69

    alp69 Форумчанин

    33. Управление двумя нагрузками с помощью импульсных реле. Контроль состояния нагрузок.

    UPD 17.06.2016 - устройство собрано, работает.
    подробности здесь


    UPD 06.09.16 - устройство введено в эксплуатацию 26.08.2016
    Новая версия здесь.
    ВНИМАНИЕ!!!
    В новой версии изменена принципиальная схема. Соответственно плата разведена иначе. Логика работы прежняя.



    Возникла задача продублировать выключатели освещения дистанционным управлением. Причем нужно это сделать так, чтобы в случае выхода из строя дистанционного управления, основное управление не ощутило этого.
    Выбор пал на схему проходного выключателя, в котором один выключатель – ручной, а роль второго выполняет импульсное реле (конкретно – E256.1-230) в форм-факторе под DIN-рейку.

    Импульсное реле (2 шт. - по одному на каждую нагрузку) получает управляющий импульс путем кратковременной (0,25 сек.) подачи ~220 вольт на катушку посредством замыкания контактов промежуточного реле, управляемого ESP-12Е. Схема контроля (их тоже две - по числу нагрузок) запроектирована как источник постоянного напряжения AC220 > DC5, выполненный по схеме с балластным конденсатором, вход которого подключен в параллель управляемой нагрузке, а выход – через оптопару на ESP.

    Все устройство будет собрано в корпусе под DIN-рейку и помещено вместе с импульсными реле в соответствующий корпус.

    На стадии сборки, скорее всего, добавится функция замера и трансляции температуры.
     
    Последнее редактирование: 6 сен 2016
    Securbond и ИгорьК нравится это.
  14. alp69

    alp69 Форумчанин

    Устройство собрано. Работает.
    Подробности здесь
     
    Последнее редактирование: 17 июл 2016
    ИгорьК нравится это.
  15. ИгорьК

    ИгорьК Гуру

    Код надо размышлять, а прошивку давайте возьмем за правило добавлять.

    Код (Javascript):
    function swich()
        gpio.write(SwichPin,gpio.LOW)  -- подали напряжение на нужную ногу (аргумент SwichPin) импульсного реле...
        tmr.delay(250000)            -- ... и через 0,25 сек ...
        gpio.write(SwichPin,gpio.HIGH) -- ...сняли напряжение
        tmr.delay(2000000)           -- 2 сек. задержка между срабатыванием импульсного реле
                                     -- и проверкой наличия напряжения
    end
    ... ну, как-бы...
     
    Последнее редактирование: 24 май 2016
  16. alp69

    alp69 Форумчанин

    Дело в том, что у меня максимальная прошивка. Универсальна для макета. Я туда натолкал все, что можно было, чтобы под каждый макет (не доведенный проект) не заказывать новую из-за недостающей мелочи. Когда какой-то проект финиширует, тогда я уже окончательно определяюсь с необходимым содержимым и скачиваю минимально необходимую. Так как этот проект еще не окончен, выложил то, чем пользуюсь.
     

    Вложения:

  17. alp69

    alp69 Форумчанин

    Ну да, delay - моветон. Но в данном конкретном устройстве эти 0,25 и 2 сек не влияют ни на точность, ни на скорострельность, ни на кучность, ни на дальность стрельбы ;)))) А вот на размер кода - влияют (правда незначительно:))
     
  18. ИгорьК

    ИгорьК Гуру

    Тут проблема не в этом. Проблема заставить себя уйти от Сишной линейной логики к событийной.
    Оно и в Си не здорово так делать, а в Lua/JS не моветон а ошибка.
    Ошибка, потому что здесь на уровне системы реализуется псевдо многозадачность. У Вас есть функции "on". Их просто нельзя тормозить.
     
    alp69 нравится это.
  19. alp69

    alp69 Форумчанин

    Хммм. Значит еще один таймер запущу. Их там четыре осталось свободных. Про on пока не совсем понятно. Подумаем над этим, почитаем доки.
    Про Lua узнал здесь и от Вас. Это первый опыт.
    Спасибо.
     
  20. ИгорьК

    ИгорьК Гуру

    Псевдопараллельность и событийность - вот основное отличие API NodeMCU от Си. Об этом нигде не пишется, потому что вроде и так ясно. Но не нам, ардуинщикам. Проблема не в синтаксисе - его недолго изучить, а в логике этой.