РЕКЛАМА НА ФОРУМХАУС В принципе задача не сложная. Ардуина легко переварит сигналы с датчиков. Главное, что надо решить - где размещать логику управления. Я бы посоветовал разделить зоны ответственности: ардуина занимается "перекодировкой" сигналов с датчиков в команды опенхаба, а опенхаб сам принимает решения, какие команды выдавать взад на ардуину. В опенхабе есть неофициальный аддон под названием 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"); } Вот собственно и все. У нас есть скетч для ардуины. Этот скетч может общаться с опенхабом по запросу отправлять в опенхаб состояние своих кнопок, реле и датчиков в ответ на запросы опенхаба переключать реле незамедлительно информировать опенхаб о замыкании/размыкании каких-то контактов Теперь остается написать правила в опенхабе...
Что-то я прочитал это и расстроился... Не смог сходу осилить формат сайтмапа... Можно ли попросить набросать простенький примерчик кофигурации опенхаба и сюда выложить? А если он не ограничится койлами, а что-то типа датчиков температуры еще прикрутить...
Вот уж зря Для опенхаба писать проще чем для ардуины в 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 } }
"Кажется что-то пошло не так" (с) Диктор новостей. Тут вроде как работает... Это температура, умноженная на 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 } } А в результате - Где и что я пропустил?
Начал понимать сам процесс. Теперь только железо присоеденить и саязать все в единую систему..Вообще классная штука и очень гибкая
Домофон купил тут 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 (я вообще знаниями охотно делюсь, но не до такой же степени, тем более в мануалах все написано)
Виноват. На самом деле там у меня написано Item Number1 changed Но все равно не видно... Температура у меня передается в виде WORD - один регистр...
А в опенхаб сообщения валятся? может значение Number1 не меняется, поэтому и правило не срабатывает? И какая частота опроса слейвов в openhab. cfg?
modbus: poll=300 написал руками. Не помогло... Значение - меняется, в modbuspoll это видно... А вот как отследить, что видит опенхаб, и вообще, прилетает ли что-то я так и не понял... start-debug.bat ответа не дал... З. Ы. на странице https://code.google.com/p/openhab/wiki/ModbusTcpBinding маленькая нестыковка:
Чтобы понять, срабатывает ли правило вообще, вставьте в него после then строчку Код: logInfo("temper", "works", null) и смотрите в консоли это сообщение. Если его нет - поменяйте условие changed на received update
Начал эксперименты с койлами. Результат тот же... 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" } } Выключатель рисуется, но ничего не происходит...
Как правило, все события, летающие по шине опенхаба отображаются в когсоли, например вот так Код: 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
Код: 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