1 2 3 4 5 6 7 8 9 10 9/10 8,94оценок: 17

Smarthome - самому и бюджетно?

Тема в разделе "Умный дом", создана пользователем vores8, 31.10.09.

  1. vores8
    Регистрация:
    26.12.07
    Сообщения:
    367
    Благодарности:
    238

    vores8

    Живу здесь

    vores8

    Живу здесь

    Регистрация:
    26.12.07
    Сообщения:
    367
    Благодарности:
    238
    Адрес:
    Нижний Новгород
    В принципе задача не сложная. Ардуина легко переварит сигналы с датчиков. Главное, что надо решить - где размещать логику управления. Я бы посоветовал разделить зоны ответственности: ардуина занимается "перекодировкой" сигналов с датчиков в команды опенхаба, а опенхаб сам принимает решения, какие команды выдавать взад на ардуину.
    В опенхабе есть неофициальный аддон под названием serialstring. Я его использую как раз чтобы получать команды их ком-порта и отправлять их в опенхаб. Выглядит это примерно так.

    Каждой ноге ардуины присваиваем свой номер. С этого номера будут сниматься данные и передаваться в ком-порт. Данные будут трех типов

    вкл/выкл (для опенхабовского Switch, это то, что мы сами сможем включать/выключать из опенхаба)
    откр/закр (для опенхабовского Contact, здесь мы можем считывать только состояние)
    вещественное число (для опенхабовского Number)

    соответственно из ардуины в опенхаб будут приходить команды вида

    Код:
    myswitch:ON
    mycontact:CLOSED
    mysensor:22.56
    А что из опенхаба в ардуину? Ну во первых будем запрашивать статус

    Код:
    status
    ну и переключать конкретные свитчи (реле)

    Код:
    myswitch:ON
    На первое время хватит

    Теперь немножко покодим. Определим чисто для красоты переменные для концевых выключателей. Их (переменных) у нас 2 (по 1 на каждый выключатель)

    Код:
    #define GATE1CONTACT 5
    #define GATE2CONTACT 6
    #define GATE1CONTACTNAME "gate1contact"
    #define GATE2CONTACTNAME "gate2contact"
    
    контакты висят на D5 и D6 ардуины. В опенхабе они будут известны как gate1contact и gate2contact

    Сначала как водится setup :)
    Код:
    void setup(void)
    {
      Serial.begin(9600);
      Serial.println("server started");
    }
    
    то будем делать в loop? Сначала прочитаем, не пишет ли что-нибудь опенхаб прямо нам в ком-порт
    Код:
    String content = "";
    char character;
    
      while(Serial.available()) {
        character = Serial.read();
        content.concat(character);
        delay(10);
      }
    
    если вдруг и правда пишет
    Код:
     if (content.length() > 0) {
    ...
    }
    то внутри этого if будем обрабатывать команды. Перво наперво - обработка запроса статуса
    Код:
        if (content.equals("status")) {
    ...
    }
    Если опенхаб просит статус - ответим статусом например контакта GATE1CONTACT
    Код:
            Serial.print(GATE1CONTACTNAME);
            Serial.print(":");
            Serial.println(digitalRead(GATE1CONTACT) == LOW ? "CLOSED" : "OPEN");
            delay(500);
    
    То есть с контакта уйдет в ком-порт сообщение
    gate1contact:OPEN или gate1contact:CLOSED в зависимости от того, какой уровень на соотв ноге ардуиныю И поставим задержку в полсекунды на всякий случай, чтобы не перегружать шину опенхаба сообщениями.
    Для состояния реле код будет абсолютно тот же самый (предполагается что реле висит на ноге 4 и опенхаб его распознает под именем myrelay1)
    Код:
    Serial.print("myrelay1:");
            Serial.println(digitalRead(4) == LOW ? "OFF" : "ON");
            delay(500);
    Остается 1-wire температуры. Для него есть стандартная библиотека, можно просто ее поиспользовать. Но если совсем влом, то делаем так
    Код:
    #include <OneWire.h>
    ...
    OneWire  ds1(7);  //arduino pin 7 = data
    
    loop() {
    ...
    float data;
          if (process(&ds1, &data) == 1) {
              Serial.print("mytemperature:");
              Serial.println(data,DEC);
            }
    ...
    }
    Ну и собственно функция process (написанная на коленке, но рабочая, просто скопируйте ее к себе в скетч)
    Код:
    int process(OneWire* ds, float* value) {
      byte i;
      byte present = 0;
      byte data[12];
      byte addr[8];
    
      if ( !ds->search(addr)) {
        ds->reset_search();
        Serial.println("error searching");
        return 0;
      }
    
    
      if ( OneWire::crc8( addr, 7) != addr[7]) {
        Serial.println("error crc");
        return 0;
      }
    
      if ( addr[0] == 0x10) {
      }
      else if ( addr[0] == 0x28) {
      }
      else {
        Serial.println("error unknown sensor type");
        return 0;
      }
    
      ds->reset();
      ds->select(addr);
      ds->write(0x44,1);        // запускаем конвертацию
    
      delay(750);    // скорее всего достаточно 750ms
      // we might do a ds.depower() here, but the reset will take care of it.
    
      present = ds->reset();
      ds->select(addr); 
      ds->write(0xBE);        // считываем ОЗУ датчика
    
      for ( i = 0; i < 9; i++) {          // обрабатываем 9 байт
        data[i] = ds->read();
      }
      int HighByte, LowByte, TReading, SignBit;
      float Tc_100;
      LowByte = data[0];
      //Serial.print("LB= ");Serial.print(LowByte,HEX);
      HighByte = data[1];
      //Serial.print(" HB= ");Serial.print(HighByte,HEX);
      TReading = (HighByte << 8) + LowByte;
      //  Tc_100 = TReading * 0.05;
    
      SignBit = TReading & 0x8000;  // test most sig bit
      if (SignBit) // negative
      {
        TReading = (TReading ^ 0xffff) + 1; // 2's comp
      }
      Tc_100 = (6 * TReading) + TReading / 4;    // multiply by (100 * 0.0625) or 6.25
      *value = Tc_100 * 0.01;
      ds->reset_search();
      return 1;
    }
    
    Теперь будем получать команды по управлению например реле. Пусть реле подключено к ноге ардуино 4. Пусть опенхаб шлет нам команды на реле в виде
    Код:
    myrelay1:OFF
    тогда мы на ардуино должны добавить код типа такого
    Код:
    if (content.equals("status")) {
    ...
    } else if (content.startsWith("myrelay1:")) {
    if (content.endsWith("OFF")) {
       digitalWrite(4, LOW);
    } else if (content.endsWith("ON")) {
       digitalWrite(4, HIGH);
    }
    }
    Последнее добавление - передача в опенхаб сигналов от кнопок. Заводим переменную, чтобы хранить предыдущее значение. Пусть кнопка висит на ноге ардуины 8.

    Код:
    int mybuttonstate = LOW;
    ...
    setup()
    ...
    loop()
    где-нибудь в конце loop пишем
    Код:
    int mybuttonnewstate = digitalRead(8);
    if (mybuttonstate != mybuttonnewstate) {
      mybuttonstate = mybuttonnewstate;
    Serial.print("mybutton:");
    Serial.println(mybuttonstate == LOW ? "OPEN" : "CLOSED");
    }
    Вот собственно и все. У нас есть скетч для ардуины. Этот скетч может общаться с опенхабом
    • по запросу отправлять в опенхаб состояние своих кнопок, реле и датчиков
    • в ответ на запросы опенхаба переключать реле
    • незамедлительно информировать опенхаб о замыкании/размыкании каких-то контактов

    Теперь остается написать правила в опенхабе...
     
    Последнее редактирование модератором: 12.11.13
  2. Shemnik69
    Регистрация:
    10.04.13
    Сообщения:
    119
    Благодарности:
    78

    Shemnik69

    Это Я

    Shemnik69

    Это Я

    Регистрация:
    10.04.13
    Сообщения:
    119
    Благодарности:
    78
    Адрес:
    Саратов
    Прочитал...:faq: буду вечером пробовать...
     
  3. kosmas
    Регистрация:
    22.07.11
    Сообщения:
    89
    Благодарности:
    7

    kosmas

    Живу здесь

    kosmas

    Живу здесь

    Регистрация:
    22.07.11
    Сообщения:
    89
    Благодарности:
    7
    Адрес:
    Питер
    Что-то я прочитал это и расстроился... Не смог сходу осилить формат сайтмапа... :(
    Можно ли попросить набросать простенький примерчик кофигурации опенхаба и сюда выложить?
    А если он не ограничится койлами, а что-то типа датчиков температуры еще прикрутить...
     
  4. vores8
    Регистрация:
    26.12.07
    Сообщения:
    367
    Благодарности:
    238

    vores8

    Живу здесь

    vores8

    Живу здесь

    Регистрация:
    26.12.07
    Сообщения:
    367
    Благодарности:
    238
    Адрес:
    Нижний Новгород
    Вот уж зря :) Для опенхаба писать проще чем для ардуины :)

    в openhab. cfg

    Код:
    modbus:tcp.slave4.connection=192.168.6.181:502
    modbus:tcp.slave4.id=1
    modbus:tcp.slave4.start=33
    modbus:tcp.slave4.length=2
    modbus:tcp.slave4.type=holding
    считываем 2 регистра в Number1 и Number2. В айтемс пишем
    Код:
    Number Temperature "Temperature [%.1f °C]"
    Number Number1 {modbus="slave4:0"}
    Number Number2 {modbus="slave4:1"}
    В rule пишем

    Код:
    rule "temper" when
    Item Number1 changed or
    Item Number2 changed
    then
    var n1 = Number1.state as DecimalType
    var n2 = Number2.state as DecimalType
    var result = (n1 * 65536 + n2) / 10000000
    Temperature.sendCommand(result)
    end
    ну а в сайтмап в нужном месте

    Код:
    Text item=Temperature
    и все :)

    А, ну да, самый простой сайтмап
    Код:
    sitemap my label="Отопление"
    {
            Frame {
                Text item=Temperature
        }
    }
    
     
    Последнее редактирование модератором: 13.11.13
  5. kosmas
    Регистрация:
    22.07.11
    Сообщения:
    89
    Благодарности:
    7

    kosmas

    Живу здесь

    kosmas

    Живу здесь

    Регистрация:
    22.07.11
    Сообщения:
    89
    Благодарности:
    7
    Адрес:
    Питер
    "Кажется что-то пошло не так" (с) Диктор новостей.

    Untitled-1.jpg

    Тут вроде как работает... Это температура, умноженная на 100. Т. е. реально - 41.00 градус.

    openhub. cfg:
    Код:
    folder:items=10,items
    folder:sitemaps=10,sitemap
    folder:rules=10,rules
    folder:scripts=10,script
    folder:persistence=10,persist
    
    modbus:tcp.slave4.connection=192.168.100.100:502
    modbus:tcp.slave4.id=10
    modbus:tcp.slave4.start=1
    modbus:tcp.slave4.length=1
    modbus:tcp.slave4.type=holding
    demo. items:
    Код:
    Number Temperature "Temperature [%.1f °C]"
    Number Number1 {modbus="slave4:0"}
    demo. rules:
    Код:
    rule "temper"
        when
            Item Number1
        then
        var n1 = Number1.state as DecimalType
        var result = n1 / 100
        Temperature.sendCommand(result)
    end
    demo. sitemap
    Код:
    sitemap my label="Отопление"
    {
            Frame {
                Text item=Temperature
        }
    }
    А в результате -
    Untitled-2.jpg

    Где и что я пропустил?
     
  6. Shemnik69
    Регистрация:
    10.04.13
    Сообщения:
    119
    Благодарности:
    78

    Shemnik69

    Это Я

    Shemnik69

    Это Я

    Регистрация:
    10.04.13
    Сообщения:
    119
    Благодарности:
    78
    Адрес:
    Саратов
    Начал понимать сам процесс. Теперь только железо присоеденить и саязать все в единую систему..Вообще классная штука и очень гибкая
     
  7. Chwarckopff
    Регистрация:
    08.07.13
    Сообщения:
    1
    Благодарности:
    0

    Chwarckopff

    Новичок

    Chwarckopff

    Новичок

    Регистрация:
    08.07.13
    Сообщения:
    1
    Благодарности:
    0
    Адрес:
    Адрес
    Подскажите пожалуйста, где вы его купили ?
    Спасибо!
     
  8. vores8
    Регистрация:
    26.12.07
    Сообщения:
    367
    Благодарности:
    238

    vores8

    Живу здесь

    vores8

    Живу здесь

    Регистрация:
    26.12.07
    Сообщения:
    367
    Благодарности:
    238
    Адрес:
    Нижний Новгород
    Домофон купил тут http://tador.com/

    По поводу температуры и модбаса. сам я такими вещами не балуюсь, но

    если температура задается вещественным числом, то значения хранятся в двух последовательных holding регистрах. И извлекать их надо вот так
    Код:
    rule "temper" when
    Item Number1 changed or
    Item Number2 changed
    then
    var n1 = Number1.state as DecimalType
    var n2 = Number2.state as DecimalType
    var temp = n1 * 256 * 256 + n2
    var sign = -temp.shiftRight(31).bitwiseNot()
    var exponent =  temp.shiftRight(23).bitwiseAnd(255) - 127
    var mantissa = temp.bitwiseAnd(8388607).doubleValue / 8388608 + 1
    var result = sign * mantissa * 1.shiftLeft(exponent)
    Temperature.sendCommand(result)
    end
    и не забыть в начале файла правил добавить

    Код:
    import java.lang.Math
    
    ессно что не так
    Код:
    rule "temper"
        when
            Item Number1 
        then
        var n1 = Number1.state as DecimalType
        var result = n1 / 100
        Temperature.sendCommand(result)
    end
    Item Number1 - бессмысленная конструкция. Правило включается по какому нибудь действию, так что должно быть что-то вроде
    Item Number1 changed
    или
    Item Number1 received update
    или
    Item Number1 received command

    (я вообще знаниями охотно делюсь, но не до такой же степени, тем более в мануалах все написано)
     
    Последнее редактирование модератором: 13.11.13
  9. kosmas
    Регистрация:
    22.07.11
    Сообщения:
    89
    Благодарности:
    7

    kosmas

    Живу здесь

    kosmas

    Живу здесь

    Регистрация:
    22.07.11
    Сообщения:
    89
    Благодарности:
    7
    Адрес:
    Питер
    Виноват. На самом деле там у меня написано
    Item Number1 changed

    Но все равно не видно...
    Температура у меня передается в виде WORD - один регистр...
     
  10. vores8
    Регистрация:
    26.12.07
    Сообщения:
    367
    Благодарности:
    238

    vores8

    Живу здесь

    vores8

    Живу здесь

    Регистрация:
    26.12.07
    Сообщения:
    367
    Благодарности:
    238
    Адрес:
    Нижний Новгород
    А в опенхаб сообщения валятся? может значение Number1 не меняется, поэтому и правило не срабатывает? И какая частота опроса слейвов в openhab. cfg?
     
  11. kosmas
    Регистрация:
    22.07.11
    Сообщения:
    89
    Благодарности:
    7

    kosmas

    Живу здесь

    kosmas

    Живу здесь

    Регистрация:
    22.07.11
    Сообщения:
    89
    Благодарности:
    7
    Адрес:
    Питер
    modbus: poll=300 написал руками. Не помогло... :(
    Значение - меняется, в modbuspoll это видно...

    А вот как отследить, что видит опенхаб, и вообще, прилетает ли что-то я так и не понял... start-debug.bat ответа не дал...

    З. Ы. на странице https://code.google.com/p/openhab/wiki/ModbusTcpBinding маленькая нестыковка:
     
    Последнее редактирование: 13.11.13
  12. vores8
    Регистрация:
    26.12.07
    Сообщения:
    367
    Благодарности:
    238

    vores8

    Живу здесь

    vores8

    Живу здесь

    Регистрация:
    26.12.07
    Сообщения:
    367
    Благодарности:
    238
    Адрес:
    Нижний Новгород
    Чтобы понять, срабатывает ли правило вообще, вставьте в него после then строчку
    Код:
    logInfo("temper", "works", null)
    и смотрите в консоли это сообщение. Если его нет - поменяйте условие changed на received update
     
  13. kosmas
    Регистрация:
    22.07.11
    Сообщения:
    89
    Благодарности:
    7

    kosmas

    Живу здесь

    kosmas

    Живу здесь

    Регистрация:
    22.07.11
    Сообщения:
    89
    Благодарности:
    7
    Адрес:
    Питер
    Начал эксперименты с койлами. Результат тот же... :(
    3.jpg
    openhub. cfg
    Код:
    folder:items=10,items
    folder:sitemaps=10,sitemap
    folder:rules=10,rules
    folder:scripts=10,script
    folder:persistence=10,persist
    
    modbus:poll=300
    modbus:tcp.slave4.connection=192.168.100.100
    modbus:tcp.slave4.port=502
    modbus:tcp.slave4.id=10
    modbus:tcp.slave4.start=1
    modbus:tcp.slave4.length=1
    modbus:tcp.slave4.type=holding
    
    modbus:tcp.slave3.connection=192.168.100.100
    modbus:tcp.slave3.port=502
    modbus:tcp.slave3.id=10
    modbus:tcp.slave3.start=0
    modbus:tcp.slave3.length=3
    modbus:tcp.slave3.type=coil
    demo. items
    Код:
    Number Temperature "Temperature [%.1f °C]"
    Number Number1 {modbus="slave4:0"}
    
    Switch MySwitch1 "My Modbus Switch" (ALL) {modbus="slave3:2"}
    demo. sitemap
    Код:
    sitemap my label="Отопление"
    {
            Frame {
                Text item=Temperature
                Switch item=MySwitch1 label="Switch 1"
        }
    }
    4.jpg

    Выключатель рисуется, но ничего не происходит... :(
     
  14. vores8
    Регистрация:
    26.12.07
    Сообщения:
    367
    Благодарности:
    238

    vores8

    Живу здесь

    vores8

    Живу здесь

    Регистрация:
    26.12.07
    Сообщения:
    367
    Благодарности:
    238
    Адрес:
    Нижний Новгород
    Как правило, все события, летающие по шине опенхаба отображаются в когсоли, например вот так

    Код:
    2013-11-10 23:26:23 - HumidityKitchen state updated to 35
    2013-11-10 23:26:23 - Serial state updated to id=706;type=h;value=35
    2013-11-10 23:26:36 - Serial state updated to id=307;type=t;value=22.3
    2013-11-10 23:26:36 - TemperatureMasterBedroom state updated to 22.3
    2013-11-10 23:26:36 - HumidityMasterBedroom state updated to 43
    2013-11-10 23:26:36 - Serial state updated to id=307;type=h;value=43
    2013-11-10 23:26:52 - Serial state updated to id=107;type=t;value=19.3
     
  15. kosmas
    Регистрация:
    22.07.11
    Сообщения:
    89
    Благодарности:
    7

    kosmas

    Живу здесь

    kosmas

    Живу здесь

    Регистрация:
    22.07.11
    Сообщения:
    89
    Благодарности:
    7
    Адрес:
    Питер
    Код:
    08:02:58.444 DEBUG o.o.i.s.i.DiscoveryServiceImpl[:63] - Registering new service _openhab-server._tcp.local. at port 8080
    08:03:05.235 DEBUG o.o.i.s.i.DiscoveryServiceImpl[:63] - Registering new service _openhab-server-ssl._tcp.local. at port 8443
    08:03:06.075 INFO  o.o.m.c.i.ModelRepositoryImpl[:99] - Loading model 'demo.sitemap'
    08:03:06.165 INFO  o.o.m.c.i.ModelRepositoryImpl[:99] - Loading model 'demo.items'
    08:03:06.175 DEBUG o.o.m.i.i.GenericItemProvider[:154] - Read items from model 'demo.items'
    08:03:07.955 INFO  o.o.u.w.i.s.WebAppServlet[:99] - Started Classic UI at /openhab.app
    08:03:08.325 DEBUG o.o.m.r.i.RuleModelActivator[:62] - Registered 'rules' configuration parser
    08:03:08.345 DEBUG o.o.m.r.i.engine.RuleEngine[:98] - Started rule engine
    08:03:16.276 INFO  o.o.m.c.i.ModelRepositoryImpl[:99] - Loading model 'demo.rules'
    08:03:39.183 INFO  runtime.busevents[:42] - MySwitch1 received command ON
    08:03:45.639 INFO  runtime.busevents[:42] - MySwitch1 received command OFF
    08:04:36.376 INFO  o.o.m.c.i.ModelRepositoryImpl[:117] - Refreshing model 'demo.rules'
    Это я пощелкал выключателем и поменял changed на received update.

    файл demo. rules
    Код:
    import org.openhab.core.library.types.DecimalType
    
    rule "temper"
        when
            Item Number1 received update
        then
        logInfo("temper", "works", null)
        var n1 = Number1.state as DecimalType
        var result = n1 / 100
        Temperature.sendCommand(result)
    end