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

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

  1. alp69

    alp69 Форумчанин

    Ну это можно флагом отрегулировать. Чтобы публикации ждали готовности брокера.
    В ver."timer" повторный коннект не роняет скрипт при повторном вызове функции таймером 1?
     
  2. dimm71

    dimm71 Нерд

    Да. Даже после перезагрузки. Вылезают такие ошибки когда я нажимаю на изменение час/мин. В браузере данные не выставляются, а в лог ОН сыпятся эти ошибки
     
  3. ИгорьК

    ИгорьК Гуру

    Вот я и сделал этот флаг. Проблема автоконнекта в том, что он этот флаг не сбрасывает очень и очень долго. В результате, другие части программы могут напихать на отправку неодъемное количество информации.
    Посмотрите внимательно первое видео - после какого времени сбрасывается флаг когда я принудительно выключаю брокер. На втором видео флаг сбрасывается почти моментально.
    Я экспериментировал с автоконнектом, и никогда не дожидался сработки колбэка. Только поверив Вам увидел что он срабатывает и сбрасывает в конце концов флаг. Раньше считал что этого не происходит - вешал событие на потерю коннекта и... система зависала :)

    При нулевом автоконнекте скрипт не падает.
    Ваш вариант вполне рабочий, но при том, что скрипт вызывает отправку сообщений достаточно редко, и автоконнект успевает выставить флаг. По моим наблюдением это происходит от 40 до 50 секунд.
    Проверьте сами, скрипты что я использовал положил, как делал - хорошо видно. На машине брокер останавливал и запускал команlами:
    Код (Bash):
    service mosqutto stop
    service mosqutto start
     
    Последнее редактирование: 6 фев 2017
  4. ИгорьК

    ИгорьК Гуру

    А вот ссыль полезная для заливки прошивок на ESP-8266: https://github.com/marcelstoer/nodemcu-pyflasher/releases
    Программа недавно обновилась, может, боян, но у меня это залило прошивку, которую раньше залить не удалось:
    pyflasher.jpg
     
  5. alp69

    alp69 Форумчанин

    Я wifi отключал. Точнее давал модулю команду на подключение к отсутствующей сети.
    Да я не спорю. Это видно. Только у меня почему-то события m: оn не отрабатываются. Сегодня еще поковыряю.
    Цель моего примера скорее научно-познавательная. Код писАл с задачей самообучения. Ну а на написанный скелет мяска-то понавешаем :D
     
  6. ИгорьК

    ИгорьК Гуру

    Не отрабатываются. И в этом прикол тоже.
    Если вы добавляете callback на "connect", то on : "connect" - не отрабатывается.
    Если вы добавляете callback на "offline" - on : "offline" - не отрабатывается. У меня его и нет.
     
  7. alp69

    alp69 Форумчанин

    Так вот и хотелось бы понять почему. Ведь в доках четко сказано "регистрация функции, выполняемой по событию offline, connect или message". Косяк. Но чей? Наш или авторов прошивки? Или модулю прошивки mqtt не хватает еще какого-то модуля. К примеру net.
    Буду разбираться. Хотелось бы дожать. Точнее выжать максимум из заложенного в прошивку штатного функционала.
     
    ИгорьК нравится это.
  8. ИгорьК

    ИгорьК Гуру

    Это, скорее, недоработка документации.
    Установил опытным путем.
     
    Последнее редактирование: 6 фев 2017
  9. alp69

    alp69 Форумчанин

    Гляньте. Там счетчик все покажет при управлении москитом (старт/стоп).
    Код (Lua):
    ClientID = "test_module"
    keep_alive = 10
    BrokerIP = "192.168.0.110"
    BrokerPort = 1883
    m = mqtt.Client(ClientID, keep_alive)
    m:lwt("/myhome/test_mod_net_state", "offline", 0, 0)

    -- секундомер
    pub = false
    count = 0
    tmr.alarm(1, 1000, 1, function()
    count = count + 1
    print("pub=",pub, count, "сек.")
    end)
    --
    function connecting()

        m:connect(BrokerIP, BrokerPort, 0, 1,
            function()
                print("CONNECTED", count, "сек.")
                pub = true
                m:publish("/myhome/test_mod_net_state","online",0,0)
                end,
            function()
                print("LOST CONNECTION", count, "сек.")
                m:close()
                connecting()    
        end)
    end

    m:on("offline", function(con)
    pub=false
    end)

    connecting()
    На старт всего 5 секунд. Потом - как часы! Никаких задержек.
    Нам же важно своевременное изменение значения переменной pub? И чтобы оно соответствовало действительности. Вроде бы все соответствует. И не падает при повторном коннекте.
     
    Последнее редактирование: 6 фев 2017
    ИгорьК нравится это.
  10. alp69

    alp69 Форумчанин

    Пятисекундная задержка у меня шла при обрыве при переходе на другую сеть wifi и возврате обратно. Но оно и объяснимо. Это задержка не из-за кода, а из-за времени подхвата сети.
     
  11. dimm71

    dimm71 Нерд

    Мужики, заблудился в 3-х соснах :)
    Подскажите, где накосячил
    Код (C++):
    tmr.alarm(6, 60000, 1, function()
        if file.open("time.txt", "r") then
            Hs = file.readline()
            Ms = file.readline()
            He = file.readline()
            Me = file.readline()
    --        print(Hs, Ms, He, Me)
            file.close()
        end
    tm = rtctime.epoch2cal(rtctime.get()+GMT)
    hours = string.format("%02d", tm["hour"])
    minutes = string.format("%02d", tm["min"])
    if (hours == Hs and minutes <= Ms) then
      print("Timer Start")
      gpio.write(4,gpio.LOW)
      publ(topic, data=="ON1")
      elseif (hours == He and minutes <= Me) then
      print("Timer Stop")
      gpio.write(4,gpio.HIGH)
      publ(topic, data=="OFF1")
      else
      print("Timer Error")

    end
    end)
    Не обрабатывается IF. Print всё время выдает "Timer Error"

    В файле time.txt построчно указаны цифры час, мин, час, мин
     
  12. alp69

    alp69 Форумчанин

    А Вы выведите
    Код (Lua):
    print(Hs, Ms, He, Me, hours, munutes)
    после
    Код (Lua):
    print("Timer Error")
    и все увидите.
     
  13. dimm71

    dimm71 Нерд

    Все переменные отображаются правильно. Где то в другом косяк
     
  14. ИгорьК

    ИгорьК Гуру

    Разберитесь с типом данных. У Вас стринги, а Вы производите операции как над числами. Преобразуйте при помощи tonumber().
     
  15. ИгорьК

    ИгорьК Гуру

    Теперь тест на потерю wifi:

     
  16. dimm71

    dimm71 Нерд

    Спасибо. Преобразовал в числа и все заработало.
    Теперь буду разбираться как передать из ОН данные, чтобы записать их в файл time.txt. Вроде где то в этой теме встречал что то подобное. Но не помню где.

    И ещё косяк. По времени все отрабатывается, но обратной связи в ОН нет. При включении не переводится переключатель в положении ON. В какую сторону копать?
    Код (C++):
    Broker="www.***********.ru"
    port=1883
    myClient="ESPSwitch"
    login="*******"
    pass="******"
    publish = false

    m = mqtt.Client(myClient, 180, login, pass)
    m:lwt("/lwt", myClient, 0, 0)
    --
    function connecting()
        if wifi.sta.status() == 5 and wifi.sta.getip() ~= nil then
                print("Got WiFi, Got IP-adress")
                m:connect(Broker, port, 0, 0, function(conn)
                    print("Connected")
                    publish = true
                    m:subscribe({[myClient.."/myhome/lamp01/command"]=0,[myClient.."/myhome/lamp02/command"]=0}, function(conn)
                    print("Subscribed")
                    Main_prog()
                    run_SNTP()
                    run_main_time()
                    SNTP()
                    end)
                end)
        elseif wifi.sta.status() ~= 5 or wifi.sta.getip() == nil then --
            print("Not WI-FI && IP-adress, Start AP")
            publish = false
            search_wifi()
        end
    end
    --
    function search_wifi()
        tmr.stop(2)
        tmr.stop(3)
        tmr.stop(4)
    wifi.setmode(wifi.STATIONAP)
    wifi.ap.config({ssid="ESPSwitch", pwd="*******"})
    enduser_setup.manual(true)
      enduser_setup.start(
      function()
      print("Connected WiFi. IP-adress:" .. wifi.sta.getip())
      end,
      function(err, str)
      print("enduser_setup: Err #" .. err .. ": " .. str)
      end)
        tmr.alarm(1, 5000, 1, function()
            if wifi.sta.getip() ~= nil then
            enduser_setup.stop()
            wifi.setmode(wifi.STATION)
            print("Got IP-adress. AP Stop")
            publish = true
            tmr.start(2)
            tmr.start(3)
            tmr.start(4)
            tmr.stop(1)
            connecting()
            end
        end)
    end
    --
    m:on("offline", function(con)
        connecting()
    end)

    function publ(topic, data)
        if topic ~= nil and data ~= nil then
    --        m: publish(myClient.."/myhome/"..topic.."/state",data,0,0)
            m: publish(topic.."/state",data,0,0)
            print("Send OK!:" .. topic .. ":" .. data)
        else
            print("Send Error!")
        end
    end

    function publ2(topic, data)
        if topic ~= nil and data ~= nil then
    --        m: publish(myClient.."/myhome/"..topic.."/state",data,0,0)
            m: publish(topic.."/command",data,0,0)
            print("Send OK!:" .. topic .. ":" .. data)
        else
            print("Send Error!")
        end
    end

    m:on("message", function(conn, topic, data)
      print("Recieved:" .. topic .. ":" .. data)
    if (data=="ON1") then
      print("Enabling LED")
      gpio.write(4,gpio.LOW)
      publ(topic, data)
      elseif (data=="OFF1") then
      print("Disabling LED")
      gpio.write(4,gpio.HIGH)
      publ(topic, data)
      elseif (data=="ON2") then
      print("Enabling LED")
      gpio.write(3,gpio.LOW)
      publ(topic, data)
      elseif (data=="OFF2") then
      print("Disabling LED")
      gpio.write(3,gpio.HIGH)
      publ(topic, data)
    --  else
    --  print("Invalid - Ignoring")
    end
    --
    --
    end)

    ---[[
    function publish_data()
        print("Publish Info")
        if wifi.sta.status() == 5 and wifi.sta.getip() ~= nil then
             local ip = wifi.sta.getip()
             local vv = 0.01*math.floor(100*adc.readvdd33()/1000)            
             m:publish(myClient.."/myhome/napragometr",vv,0,0)
             print("Volt "..vv.." published!")
             m:publish(myClient.."/myhome/ip_adress",ip,0,0)
             print("IP "..ip.." published!")
             ip = nil
             vv = nil
        else
            connecting()    
          end
    end


    function Main_prog()
         print("Main  program")
         tmr.alarm(2, 900000, 1, publish_data )
    end

    function run_main_time()
         print("Main  program time")
         tmr.alarm(4, 60000, 1, publish_time )
    end

    --SNTP
    GMT = 3600*3 -- 3 hour
    rtctime.set(0, 0)

    function SNTP()
        print (rtctime.get ())
        sntp.sync('0.ru.pool.ntp.org',
      function(sec,usec,server)
        print('sync', sec, usec, server)
        print (rtctime.get ())
        end,
      function()
       print('failed SNTP!')
      end)
    end

    function TIME()
    tm = rtctime.epoch2cal(rtctime.get()+GMT)
    vvv = string.format("%02d.%02d.%04d %02d:%02d", tm["day"], tm["mon"], tm["year"], tm["hour"], tm["min"])
    end

    function publish_time()
        if wifi.sta.status() == 5 and wifi.sta.getip() ~= nil then
             TIME()
             m:publish(myClient.."/myhome/time",vvv,0,0)
             tm = nil
             vvv = nil
          end
    end

    function run_SNTP()
         tmr.alarm(3, 3600000, 1, SNTP)
         print("Synchro  SNTP")
    end
    --//////////////////////////////////////////////////////////////////////
    tmr.alarm(6, 60000, 1, function()
        if file.open("time.txt", "r") then
            Hs = tonumber(file.readline())
            Ms = tonumber(file.readline())
            He = tonumber(file.readline())
            Me = tonumber(file.readline())
    --        print(Hs, Ms, He, Me)
            file.close()
        end
    tm = rtctime.epoch2cal(rtctime.get()+GMT)
    hours = tonumber(string.format("%02d", tm["hour"]))
    minutes = tonumber(string.format("%02d", tm["min"]))
    if (hours == Hs and minutes >= Ms) then
      print("Timer Start")
      data = "ON1"
      topic = "ESPSwitch/myhome/lamp01"
      publ2(topic, data)
    --  print(topic, data)
      elseif (hours == He and minutes == Me) then
      print("Timer Stop")
      data = "OFF1"
      topic = "ESPSwitch/myhome/lamp01"
      publ2(topic, data)
    --  print(topic, data)
      else
      print("Timer Error")
    end
    end)
    --//////////////////////////////////////////////////////////////////////
    connecting()
     
    Последнее редактирование: 7 фев 2017
  17. alp69

    alp69 Форумчанин

    Во. Я тоже сижу сейчас голову ломаю над этим. Синхронно работаем :D
    Но пока без Wi-Fi код выглядит так:
    Код (Lua):
    ClientID = "test_module"
    keep_alive = 10
    BrokerIP = "192.168.0.110"
    BrokerPort = 1883
    m = mqtt.Client(ClientID, keep_alive)
    m:lwt("/myhome/test_mod_net_state", "offline", 0, 0)

    m:connect(BrokerIP, BrokerPort, 0, 1,
        function() pub = true print("ON-Line", count.." сек.")
    end)

    m:on("offline", function() print("OFF-Line", count.." сек.") pub=false
    end)

    -- секундомер
    pub = false
    count = 0
    tmr.alarm(1, 1000, 1, function()
    count = count + 1
    print("pub=",pub, count.." сек.")
    end)
    Код (Lua):
    ClientID = "test_module"
    keep_alive = 10
    BrokerIP = "192.168.0.110"
    BrokerPort = 1883
    m = mqtt.Client(ClientID, keep_alive)
    m:lwt("/myhome/test_mod_net_state", "offline", 0, 0)
    m:connect(BrokerIP, BrokerPort, 0, 1, function() pub = true end)
    m:on("offline", function() pub=false end)
     
    Последнее редактирование: 7 фев 2017
  18. alp69

    alp69 Форумчанин

    Нда... развлекаться с модулем wifi прошивки NodeMCU можно различными способами. Мне приглянулся мониторинг событий.
    С контролем потери Wi-Fi код выглядит так:
    Код (Lua):

    ClientID = "test_module"
    keep_alive = 10
    BrokerIP = "192.168.0.110"
    BrokerPort = 1883
    m = mqtt.Client(ClientID, keep_alive)
    m:lwt("/myhome/test_mod_net_state", "offline", 0, 0)

    function connect()
        m:connect(BrokerIP, BrokerPort, 0, 1,
            function()  print("ON-Line", count.." сек.")
            pub=true
        end)

        m:on("offline", function() print("OFF-Line", count.." сек.")
            pub=false
        end)
    end

    wifi.eventmon.register(wifi.eventmon.STA_CONNECTED, function()
        print("STA - CONNECTED")
        m:close()
        connect()
    end)

    wifi.eventmon.register(wifi.eventmon.STA_DISCONNECTED, function()
        print("STA - DISCONNECTED")
        pub = false
    end)

    -- секундомер
    pub = false
    count = 0
    tmr.alarm(1, 1000, 1, function()
    count = count + 1
    print("pub=",pub, count.." сек.")
    end)
     
    Код (Lua):

    ClientID = "test_module"
    keep_alive = 10
    BrokerIP = "192.168.0.110"
    BrokerPort = 1883
    m = mqtt.Client(ClientID, keep_alive)
    m:lwt("/myhome/test_mod_net_state", "offline", 0, 0)

    function connect()
    m:connect(BrokerIP, BrokerPort, 0, 1, function() pub=true end)
    m:on("offline", function() pub=false end)
    end

    wifi.eventmon.register(wifi.eventmon.STA_CONNECTED,
    function() m:close() connect() end)
    wifi.eventmon.register(wifi.eventmon.STA_DISCONNECTED,
    function() pub = false
    end)
    На восстановление связи с брокером после включения родной сети wifi у меня уходит от 3 до 10 сек. Это время, необходимое ESP-12S (в моем случае) для подхвата wifi. Причем pub становится true только при наличии связи с брокером.
    Используя мониторинг событий wifi, можно в основном коде уже не ставить проверку типа
    Код (Lua):
    if wifi.sta.status() == 5 ...
    Достаточно флага pub.
    Ваше мнение? :)

    P.S. Примитивная ежесекундная проверка node.heap() показывает, что память не течет.
     
    Последнее редактирование: 8 фев 2017
  19. ИгорьК

    ИгорьК Гуру

    Развлекаться можно, безусловно, любыми способами :) Мое мнение - использование таймера. Таймеров теперь можно создавать много и никакими цифрами мы не ограничены. Таймер создается при потере и уничтожается после восстановления соединения.
    Если говорить о мониторинге событий - это такие же таймеры, которые уже постоянно висят в памяти и работают все время. Не думаю, что это упрощает жизнь системе.
    И автоконнект - тоже, кстати, таймер.
     
  20. alp69

    alp69 Форумчанин

    Не спорю. И ни в коем случае не умаляю Ваших усилий в разработке данной темы. Мое частное мнение - если функционал уже есть, то его нужно использовать. Это как вечный спор физиков и лириков :D
    Да, таймеры вещь хорошая. Особенно в умелых руках.
    И мы с Вами решаем одну и ту же задачу, но разными способами. Главное, что идем в одном направлении и добиваемся результата!;)