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

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

  1. ИгорьК

    ИгорьК Гуру

    25. nooLite MR1132.

    Закончил описание работы с приемником nooLite MR1132 + Iskra JS на своем сайте. Приглашаю в гости.
     
    Последнее редактирование: 22 апр 2016
  2. ИгорьК

    ИгорьК Гуру

    26. Логгирование редких событий.
    Если у Вас пару раз в день включается уличный фонарь или существуют другие редкие аналогичные события, то строить графики нет смысла. Особенно, если, например, состояние датчика 0 и 1. Лучше вести логи. Один из вариантов - ниже.
    Считаем, что у вас установлен OpenHab через apt-get.
    1. Идем в директорию:
    Код (Bash):
    cd /usr/share/openhab/webapps/static
    2. Создаем там файл, например 433log.sh
    Код (Bash):
    touch 433log.sh
    chmod +x 433log.sh
    3. Наполняем файл содержимым:
    Код (Bash):
    cat /usr/share/openhab/logfiles/events.log  | grep "arduino433Signal state" >> /usr/share/openhab/webapps/static/433log.txt
    cat /usr/share/openhab/logfiles/openhab.log | grep WARN > /usr/share/openhab/webapps/static/warnlog.txt
    cat /usr/share/openhab/logfiles/openhab.log | grep ERROR > /usr/share/openhab/webapps/static/errorlog.txt
     
    "arduino433Signal state" - Это выборка из файла events.log событий, случившихся с итемом arduino433Signal . Эта выборка перенаправляется в файл 433log.txt, причем оператор >> говорит о том, что этот файл будет добавлять информацией, а не переписываться.
    Вторая и третья строки делают выборки по сообщениям WARN и ERROR из файла openhab.log,отправляя их в самостоятельные файлы.
    4. Редактируем crontab:
    Код (Bash):
    crontab -e
    Добавляем строку:
    Код (Bash):
    59 23 * * * /var/log/openhab/433log.sh
    Каждый день в 23:59 скрипт будет исполняться, причем лог редкого датчика будет добавляться а ошибки и оповещения - перезаписываться.
    5. Идем по адресу http://ваш сайт:вашпорт/static/433log.txt и видим значения:
    433log.jpg
    Аналогично с ошибками и оповещениями.
     
    Последнее редактирование: 26 апр 2016
    alp69 нравится это.
  3. netmaster

    netmaster Гик

    1. У вас этот файлик с начала времен (запуска опенхаба). Ну так это не правильно - файлы
    логов должны хранится определенное время, а затем уничтожаться см. logrotate, а то файловая система переполнится и сервис остановится...

    2. По хорошему надо не создавать файл с нуля, а дописывать его.

    3. Мысль правильная, а вот реализация - имхо не очень см. выше. Более правильное решение скидывать отпарсенные события в базу тот-же mysql и простейшим select выдавать на чтение.

    Ну... как-то так это работает в реальных системах, логи это подсказка админу. В правильно работающей системе их должно быть минимум.
     
  4. ИгорьК

    ИгорьК Гуру

    Друже, внимательнее. У меня только файлик о редких событиях долго лежит (они действительно редкие), и то я его периодически вручную удаляю. Файлики об ошибках и предупреждениях - каждый раз (прошло)суточные.
    И да и нет. Вопрос значимости и частоты. Ваять страницу на php с запросами к mysql... мне лень(потому что нет необходимости)
    Основное содержание вчерашнего файла errorlog.txt:
    Код (C++):
    2016-04-25 15:26:16.384 [ERROR] [g.openhab.io.net.http.HttpUtil] - Fatal transport error: org.apache.commons.httpclient.NoHttpResponseException: The server export.yandex.ru failed to respond
    2016-04-25 15:26:16.385 [ERROR] [.o.b.http.internal.HttpBinding] - No response received from 'http://export.yandex.ru/weather-ng/forecasts/27612.xml'
    2016-04-25 16:07:44.407 [ERROR] [g.openhab.io.net.http.HttpUtil] - Fatal transport error: org.apache.commons.httpclient.NoHttpResponseException: The server export.yandex.ru failed to respond
    2016-04-25 16:07:44.409 [ERROR] [.o.b.http.internal.HttpBinding] - No response received from 'http://export.yandex.ru/weather-ng/forecasts/27612.xml'
    2016-04-25 16:07:44.572 [ERROR] [g.openhab.io.net.http.HttpUtil] - Fatal transport error: org.apache.commons.httpclient.NoHttpResponseException: The server export.yandex.ru failed to respond
    2016-04-25 16:07:44.575 [ERROR] [.o.b.http.internal.HttpBinding] - No response received from 'http://export.yandex.ru/weather-ng/forecasts/27612.xml'
    2016-04-25 16:07:44.656 [ERROR] [g.openhab.io.net.http.HttpUtil] - Fatal transport error: org.apache.commons.httpclient.NoHttpResponseException: The server export.yandex.ru failed to respond
    2016-04-25 16:07:44.660 [ERROR] [.o.b.http.internal.HttpBinding] - No response received from 'http://export.yandex.ru/weather-ng/forecasts/27612.xml'
     
    Последнее редактирование: 26 апр 2016
  5. netmaster

    netmaster Гик

    Хм... еще раз глянул... У меня логи в архив не падают... Мда... надо сокращать кол-во тестовых опенхабов, а то сам путаться стал. На малине все нормально.

    Ну это дело личное, лень она такая... Впрочем можно ведь и из под правила (rules) файлик логов делать.
    В директорию их складывать и скрипт на удаление на дир-ю запускать.
     
  6. ИгорьК

    ИгорьК Гуру

    Какая разница как делать - файл логов, он и есть файл логов.
     
  7. ИгорьК

    ИгорьК Гуру

    27. nooLite MR1132 && ESP8266.
    Добро пожаловать на сайт.
    Здесь лишь скрипт для ESP8266, зато с пояснениями.
    Код (Lua):
    Broker="ВАШ сайт"
    port=ВАШ ПОРТ
    myClient="nooLite"
    name=myClient
    pass="pass"
    summ = 0      -- Будем высчитывать контрольную сумму
    udata =""     -- Стринг для сбора информации из UART
    ttable = {}   -- Таблица для перевода буков в их hex значения
    counter = 0   -- считаем байты из UART
    function clearAll()  -- Очистка указанного выше
        udata = ""
        ttable = {}
        counter = 0
        summ = 0
    end
    uart.on("data",1, -- с UART работаем побайтно
        function(data)
        udata = udata..data -- собираем байты в слово
        -- превращаем "буквы" в их значения таблицы UTF-8
        table.insert(ttable, string.byte(data, 1))
        counter = counter + 1 -- считаем байты
        -- MR1132 отвечает двумя способами: или OK или 11 байт
        -- вот и отделяем одно от другого
        if(udata == "OK\r\n") then
            -- причем для нашего случая на OK надо отреагировать
            -- подачей команды на остановку биндинга автоматом
            print("bind_mode_off\03")
            clearAll() -- вычищаем все и начинаем считать заново
        end
        -- а здесь устанавливаем таймер на очистку принятого из UART
        -- если количество байт не совпадет с 11 штуками
        if counter == 1 then
            tmr.alarm(3, 1000, 0, function()
               clearAll()
            end )
        end
        -- считаем контрольную сумму
        if counter < 10 then
            local d = ttable[counter]
            if d ~= nil then
                summ = summ + d
            end
        end
        -- это отладочная инструкция, если в UART выдать подряд черыте q
        -- "qqqq" - исполнение программы остановится и ее можно отлаживать
        if string.find(udata, "qqqq") ~= nil  then node.restart() end

        -- анализируем 11 байт, причем первый - 85, последний - 170 и сравниваем контрольную сумму
        if counter == 11 then
            if ttable[1] == 85 and ttable[11] == 170 and (ttable[10]-1) == bit.band(summ, 0xFF) then
                -- 21 - это когда пришла информация с датчиков, иначе это всегда другая цифра
                if ttable[4] ~= 21 then
                    -- публикуем информацию с выключателей
                    m:publish(myClient.."/"..ttable[3].."/state",ttable[4],0,0)
                else
                    -- иначе расчитываем температуру
                    local temp = 0
                    local hempH = ttable[7]
                    local hempL = ttable[6]
                    temp = bit.lshift(bit.band(hempH, 0x0F),8) + hempL
       
                    if (temp > 0x7FF) then
                        temp = temp - 0x1000
                    end
                    temp = temp * 0.1
                    -- публикуем температуру
                    m:publish(myClient.."/"..ttable[3].."/state",temp,0,0 )
                    -- есть влажность - публикуем
                    if ttable[8] ~= 0 then
                        m:publish(myClient.."/".."10"..ttable[3].."/state",ttable[8],0,0)
                    end
                end
            end
            clearAll() -- очистка всего для нового сбора информации из UART
        end
    end, 0)
    m = mqtt.Client(myClient, 180, name, pass) -- информация об mqtt клиенте
    m:lwt("/lwt", myClient, 0, 0)  -- завещание на случай...
    m:on("offline", function(con)  -- пересоединение на случай потери связи с брокером
        tmr.alarm(1, 120000, 1, function()
              m:connect(Broker, port, 0, function(conn)
                tmr.stop(1)
                m:subscribe(myClient.."/#",0, function(conn)
                end)
              end)
            collectgarbage()
        end)
    end)
    -- обработка сообения на модуль.
    -- отрабатываются только 4 топика
    -- на топике 3 необходимо указывать как сообщение
    -- номер ячейки для биндинга
    m:on("message", function(conn, topic, data)
        if (string.find(topic, "state")) == nil then
            local top = string.gsub(topic, myClient.."/","")
            local sendto = ""
            if top == "1" then
                sendto = sendto.."clear_all_cell"
            elseif top == "2" then
                sendto = sendto.."clear_one_cell_"..data
             elseif top == "3" then
                sendto = sendto.."bind_mode_cell_"..data
            elseif top == "4" then
                sendto = sendto.."bind_mode_off"
            else
                sendto = ""
                return
            end
            sendto = sendto.."\03"
            print(sendto)
        end
        sendto = ""
        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")
                  m:subscribe(myClient.."/#",0, function(conn)
                  end)
            end)
        end
    end)
     
    Да схема соединения:
    [​IMG]
    Красным - ESP8266+DS8b20 каждые 10 минут. Синим - датчик температуры и влажности PT-111.
    021.jpg
    thermo.jpg
    РТ-111 отдельно:
    020.jpg
     
    Последнее редактирование: 13 май 2016
  8. ИгорьК

    ИгорьК Гуру

    28. nooLite MT1132 && Iskra JS.
    А вот модуль Iskra JS (Espruino) для работы с передатчиком MT1132 от nooLite.

    И сложнейший код для применения:
    Код (Javascript):
    // Соеднияемся с шестым Serial
    var nooMT = require('nooMT').connect(6);

    // Отправляем команду 0 на 4 канал
    nooMT.sendNooMT(4,0);

     
    UPD. 13.05.2016. В коде была ошибочка. Заменен.
     

    Вложения:

    • nooMT01.zip
      Размер файла:
      1,2 КБ
      Просмотров:
      370
    Последнее редактирование: 13 май 2016
  9. netmaster

    netmaster Гик

    День добрый, коллеги.

    Имею след стенд. ESP->Роутер с NAT->INTERNET->MQTT брокет
    Наблюдаю следующее, неприятное:
    У Роутера отнимаем Интернет (WiFI линк работает):
    На брокере через KEEPALIVE время вижу сообщение в топике LWT - тут все как надо.
    А вот на ESP проходит более 10 минут, как в mqtt:eek:n появляется сообщение "offline". Прошивку устанавливал сборную, заказанную через сайт.

    Интересно, как быстро у Вас отрабатывается такой тест?
     
  10. ИгорьК

    ИгорьК Гуру

    Десятки раз проверял - через чуть-чуть относительно 180 как параметра в этой строчке:
    m = mqtt.Client(myClient, 180, name, pass)
    180 - это три минуты. Чаще, думаю, не надо.

    хм... Искренне думал, что Вы их сами пишете :(
     
  11. netmaster

    netmaster Гик

    Я тоже читал документацию :), а при тестах параметр KEEPALIVE который у Вас 180, у меня как не меняй 10 минут. Вот и решил спросить...

    Так это нормально, если есть проблема описать на каком софте ее получил.
     
  12. ИгорьК

    ИгорьК Гуру

    Я говорю, естественно, о тех скриптах, которые использую и публикую здесь.
     
  13. netmaster

    netmaster Гик

    Вот код взятый выше отсюда с сокращениями.

    Код (C++):
    m = mqtt.Client(MQTTCLIENTID, 30, MQTTUSER, MQTTPASS) --Объявление MQTT клиента
    m:lwt(LWT,MQTTCLIENTID.." offline", 0, 0) --Сообщение OpenHab о обрыве связи
    m:on("offline", function(conn)
    print("offline")
    tmr.alarm(1, 6000, 1, function()
      m:connect(MQTTSRV,MQTTPORT, 0, function(conn)
       print("reconnected")
       m:subscribe(SUBTOPIC,0, function(conn)
       end)
       m:publish(LWT,MQTTCLIENTID.." online",0,0)            
      end)
    end)
    collectgarbage()
    end)

    m:on("message", function(conn, topic, data) -- Если пришли данные от брокера
    print(data)
    end)

    -- Подписка у брокера
    tmr.alarm(0, 1000, 1, function()
        if wifi.sta.status() == 5 and wifi.sta.getip() ~= nil then
            tmr.stop(0)
              m:connect(MQTTSRV,MQTTPORT, 0, function(conn)
                   print("connected")
                  m:subscribe(SUBTOPIC,0, function(conn)
                  end)
                  m:publish(LWT,MQTTCLIENTID.." online",0,0)
            end)
        end
    end)
    А вот что у меня с ним получается, если не прошло 10 минут, а связь восстановилась.

    Код (C++):
    Communication with MCU...
    Got answer! AutoDetect firmware...

    NodeMCU firmware detected.
    =node.heap()
    38144
    > connected
    offline
    reconnected
    PANIC: unprotected error in call to Lua API (init.lua:24: already connected)
    c_ЗRSцвjSцfКГjо�ч

    NodeMCU custom build by frightanic.com
        branch: master
        commit: c8037568571edb5c568c2f8231e4f8ce0683b883
        SSL: false
        modules: file,mqtt,node,sntp,tmr,uart,wifi
    build     built on: 2016-05-12 09:24
    powered by Lua 5.1.4 on SDK 1.4.0
    > connected
     
    Есть ли какие мысли - софт менял на всякий. Поведение одинаковое...
     
  14. ИгорьК

    ИгорьК Гуру

    Мысли есть:
    Что там в init.lua?
     
  15. netmaster

    netmaster Гик

    Так это - оно и есть.
     
  16. ИгорьК

    ИгорьК Гуру

    Ааааааа....
    А кто будет первый таймер останавливать, когда реконнект прошел? Пушкин?
     
    Последнее редактирование: 13 май 2016
  17. netmaster

    netmaster Гик

    Стало так...
    tmr.alarm(1, 6000, 1, function()
    tmr.stop(1)
    Тогда уж 27. nooLite MR1132 && ESP8266. поправьте - слямзил оттуда.:p

    Вот в ребут уходить перестал, НО как тупил 10 минут так и тупит. Я специально отсюда скрипт взял.

    Тот, что писал я в ребут не не уходил, но тупит так-же пофиг им keepalive time :(
     
  18. ИгорьК

    ИгорьК Гуру

    Нет бы с другого места слямзить...
    Ну и лямзить - так качественнее:
    m = mqtt.Client(myClient,180, name, pass)
    Здесь три минуты. Попробуйте, сначала, их. Я понимаю, что должен в любым количеством времени правильно работать, но... Возможно какие-то особенности nodemcu, мало ли что там...
    Я все это тестирую на карманном модеме, код старый уже. Не сталкивался с таким, будет время - проверю еще раз.

    UPD. Знаете что заметил? Иногда, редко-редко движок форума что-то подъедает. Сейчас специально проверил и у себя на компе и на сайте - есть там остановка первого таймера.
     
  19. netmaster

    netmaster Гик

    На так я старался:D лямзил там где надо....
    С этого я и начал... Был рабочий скрипт, помню сам проверял все было нормально, а теперь такая ж0..

    Я пока не понимаю куда копать, сообщения кеепаливе не приходят, таймер уже давно прошел и как его не меняй - 10-11 минут до прихода offline. Мистика :mad::mad::mad:
     
  20. ИгорьК

    ИгорьК Гуру

    29. nooLIte MT1132, MR1132 && ESP8266
    Кое-что дополнительно будет здесь.
    Соединяем:
    [​IMG]
    Зашиваем:
    Код (Lua):
    Broker="ВАШ_САЙТ"
    port=ВАШ_ПОРТ
    myClient="nooLite"
    name=myClient
    pass="ВАШ_ПАРОЛЬ"
    summ = 0
    udata =""
    ttable = {}
    counter = 0
    function sendNooMT(channel, comm)
        if((comm > 15 and comm < 32) or comm > 155) then
            return;
        end
        local command = {85,80,0,0,0,0,0,0,0,0,0,170}
        command[6] = channel
        local tempcommand = comm
        if (tempcommand < 16) then
            command[3] = tempcommand
            command[4] = 0
            command[7] = 0
        else
            command[3] = 6
            command[4] = 1
            command[7] = tempcommand
        end
        local check = 0
        for i = 1, 11 do
            check = check + command[i]
        end
        check = bit.band(check, 0xFF)
        command[11] = check;
        for i = 1, 12 do
            uart.write(0, command[i])
        end
    end

    function clearAll()
        udata = ""
        ttable = {}
        counter = 0
        summ = 0
    end
    uart.on("data",1,
        function(data)
        udata = udata..data
        table.insert(ttable, string.byte(data, 1))
        counter = counter + 1
        if(udata == "OK\r\n") then
            print("bind_mode_off\03")
            clearAll()
        end
        if counter == 1 then
            tmr.alarm(0, 1000, 0, function()
               clearAll()
            end )
        end
        if counter < 10 then
            local d = ttable[counter]
            if d ~= nil then
                summ = summ + d
            end
        end
        if string.find(udata, "qqqq") ~= nil  then node.restart() end

        if counter == 11 then
            if ttable[1] == 85 and ttable[11] == 170 and (ttable[10]-1) == bit.band(summ, 0xFF) then
                if ttable[4] ~= 21 then
                    m:publish(myClient.."/"..ttable[3].."/state",ttable[4],0,0)
                else
                    local temp = 0
                    local hempH = ttable[7]
                    local hempL = ttable[6]
                    temp = bit.lshift(bit.band(hempH, 0x0F),8) + hempL
             
                    if (temp > 0x7FF) then
                        temp = temp - 0x1000
                    end
                    temp = temp * 0.1
                    m:publish(myClient.."/"..ttable[3].."/state",temp,0,0 )
                    if ttable[8] ~= 0 then
                        m:publish(myClient.."/".."10"..ttable[3].."/state",ttable[8],0,0)
                    end
                end
            end
            clearAll()
        end
    end, 0)
    m = mqtt.Client(myClient, 180, name, pass)
    m:lwt("/lwt", myClient, 0, 0)
    m:on("offline", function(con)
        tmr.alarm(1, 120000, 1, function()
              m:connect(Broker, port, 0, function(conn)
                tmr.stop(1)
                m:subscribe(myClient.."/#",0, function(conn)
                end)
              end)
            collectgarbage()
        end)
    end)
    m:on("message", function(conn, topic, data)
        if (string.find(topic, "state")) == nil then
            local top = string.gsub(topic, myClient.."/","")
            local sendto = ""
            if top == "91" then
                sendto = sendto.."clear_all_cell"
            elseif top == "92" then
                sendto = sendto.."clear_one_cell_"..data
             elseif top == "93" then
                sendto = sendto.."bind_mode_cell_"..data
            elseif top == "94" then
                sendto = sendto.."bind_mode_off"
            else
                sendNooMT(tonumber(top), tonumber(data))
                sendto = ""
                return
            end
            sendto = sendto.."\03"
            print(sendto)
        end
        sendto = ""
        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")
                  m:subscribe(myClient.."/#",0, function(conn)
                  end)
            end)
        end
    end)
     
    Для получения информации с датчиков пригодятся следующие итемы:
    Код (Bash):
    Number    Temperature_noo_4    "Температура nooLite(4) [%.2f°C]"     <temperature> (MyTest, Temperature)    { mqtt="<[mosquitto:nooLite/4/state:state:default]" }
    Number    Humi_noo_4    "Влажность nooLite(4) [%d %%]"     <weather_humidity> (MyTest, Humidity)    { mqtt="<[mosquitto:nooLite/104/state:state:default]" }
    Number    Temperature_noo_5    "Температура nooLite(5) [%.2f°C]"     <temperature> (MyTest, Temperature)    { mqtt="<[mosquitto:nooLite/5/state:state:default]" }
    Для управления выключателями создаем пару итемов для каждого:
    Код (Bash):
    Switch    Dacha_Corridor        "Корридор"                (MyTest, Dacha_group)        { mqtt=">[mosquitto:nooLite/1:command:on:2],>[mosquitto:nooLite/1:command:off:0],<[mosquitto:nooLite/9/state:state:MAP(switchNooLite.map)]" }
    Number    Dacha_Corridor_Cannel    "Корридор для анализа"        (MyTest, Dacha_group)        { mqtt="<[mosquitto:nooLite/1/state:state:default]" }
     
    И для каждого пишем правило:
    Код (Bash):
    rule "When Corridor Light is changed by command 4"            //
    when
        Item Dacha_Corridor_Cannel received update 4
    then
        if (Dacha_Corridor.state == ON) {
            postUpdate(Dacha_Corridor, OFF)
        }
        else {
            postUpdate(Dacha_Corridor, ON)
        }

    end
     
    Последнее редактирование: 17 май 2016