Arduino & OpenHAB

В предыдущей статье мы познакомились с промышленным стандартом Modbus и встроили его поддержку в Arduino, осталось состыковать устройство с платформой OpenHAB.В этот раз мы узнаем, как настроить плагин и интерфейс OpenHAB для работы с устройством, основы адресации и отладки протокола Modbus. В работе представлен эксперимент с исходным кодом плагина, а на страничке vk.com/myremoter можно обсудить открытый контроллер умного дома, который мы будем использовать в следующих экспериментах.

Но, давайте ещё раз посмотрим, какие преимущества даст нам применение стандарта Modbus? Современный дом — сложное инженерное сооружение, где управление освещением не самая главная функция. Кроме датчиков в доме устанавливают системы кондиционирования и вентиляции, управления отоплением, дренажными насосами и скважинами. Такие задачи можно поручить специальному или промышленному контроллеру, в этом случае протокол Modbus поможет объединить все инженерные системы в единую сеть, а простой и недорогой контроллер, работающий на одной с ними шине, добавит дополнительный контроль и функционал, сэкономив немало средств. В пользу этого низкие требования к оборудованию, открытость стандарта, массовость его применения, хотя, быть может, основной секрет популярности Modbus его гибкость при стыковке программ и оборудования.

Ну что же, пора приступать к работе.

Установим OpenHAB, конфигуратор и эмулятор null модемного соединения Посмотрим документацию, откроем страницу загрузки и скачаем Runtime core и Demo setup, распакуем их в C:\openhab, затем скачаем openHAB Designer и распакуем его в C:\openhab\designer. Проверим наличие Java, выполнив java –version, если Java отсутствует, выполним её установку по инструкции.Запустим OpenHAB, выполнив C:\openhab\start.bat и откроем веб-интерфейс по ссылке localhost:8080/openhab.app? sitemap=demoТеперь качаем и устанавливаем com0com, запускаем faa6903bfd3748a788eba63229484d00.JPGSetup из меню программы, смотрим, для каких последовательных портов создана виртуальная пара (у меня это COM7 + COM8). Используем их для связи OpenHAB и симулятора.

Затем установим плагин Modbus Tcp Binding который обеспечит взаимодействие OpenHAB с modbus устройствами. Откроем страницу загрузки, скачаем Addons, распакуем org.openhab.binding.modbus-1.6.2.jar в папку C:\openhab\addons.После этого настроим связь плагина с устройством, для этого запустим конфигуратор OpenHAB и откроем файл openhab_default.cfg. Найдём раздел Modbus Binding и добавим в конец этого раздела следующую информацию, затем сохраним файл.

modbus: serial.slave1.connection=COM7 modbus: serial.slave1.id=1 modbus: serial.slave1.start=0 modbus: serial.slave1.length=4 modbus: serial.slave1.type=discrete

modbus: serial.slave2.connection=COM7 modbus: serial.slave2.id=1 modbus: serial.slave2.start=16 modbus: serial.slave2.length=4 modbus: serial.slave2.type=coil

modbus: serial.slave3.connection=COM7 modbus: serial.slave3.id=1 modbus: serial.slave3.start=2 modbus: serial.slave3.length=3 modbus: serial.slave3.type=input

modbus: serial.slave4.connection=COM7 modbus: serial.slave4.id=1 modbus: serial.slave4.start=5 modbus: serial.slave4.length=3 modbus: serial.slave4.type=holding Настройки содержат 4 группы адресов сопоставленных с регистрами устройства. В каждой группе указан номер последовательного порта, modbus адрес контроллера, modbus адрес первого в группе регистра, количество регистров в группе и тип этих регистров. Группы адресов станут связующим звеном между элементами OpenHAB и устройством.Теперь настроим связь OpenHAB с регистрами устройства. Откроем в конфигураторе файл demo.items и добавим в конец этого файла следующий код:

Group FF_Modbus «Modbus» (All) Contact MB_DT0 «DT0 [MAP (en.map):%s]» (FF_Modbus){modbus=«slave1:0»} Contact MB_DT1 «DT1 [MAP (en.map):%s]» (FF_Modbus){modbus=«slave1:1»} Contact MB_DT2 «DT2 [MAP (en.map):%s]» (FF_Modbus){modbus=«slave1:2»} Contact MB_BTN «BTN [MAP (en.map):%s]» (FF_Modbus){modbus=«slave1:3»} Switch MB_CL16 «CL16» (FF_Modbus){modbus=«slave2:0»} Switch MB_CL17 «CL17» (FF_Modbus){modbus=«slave2:1»} Switch MB_CL18 «CL18» (FF_Modbus){modbus=«slave2:2»} Switch MB_LED «LED» (FF_Modbus){modbus=«slave2:3»} Number MB_INPT2 «INPT2[%d]» (FF_Modbus){modbus=«slave3:0»} Number MB_INPT3 «INPT3[%d]» (FF_Modbus){modbus=«slave3:1»} Number MB_INPT4 «INPT4[%d]» (FF_Modbus){modbus=«slave3:2»} Number MB_HOLD5 «HOLD5[%d]» (FF_Modbus){modbus=«slave4:0»} Number MB_HOLD6 «HOLD6[%d]» (FF_Modbus){modbus=«slave4:1»} Number MB_HOLD7 «HOLD7[%d]» (FF_Modbus){modbus=«slave4:2»} В первой строке определена группа FF_Modbus которая объединит добавляемые элементы. Каждый элемент задан его типом, названием, форматом текстовой надписи, списком групп в которых он состоит и настройками связи с устройством. Мы использовали элементы трёх типов — Contact, Switch, Number, а в настройках связи указали тип (modbus), имя одной из групп заданных в настройках плагина (например, slave1) и порядковый номер регистра в этой группе.Наглядно представить взаимосвязь между регистрами контроллера, обычными и логическими адресами Modbus, группами регистров в настройках плагина и элементами OpenHAB нам поможет следующая таблица.

c04a1c28b4de455696e7c436169bae1b.JPG

Настало время отобразить наши элементы в интерфейсе. Откроем в конфигураторе файл demo.sitemap и добавим в него описание двух фреймов:

Frame { Group item=FF_Modbus icon=«attic» }

Frame { Text item= MB_DT0 Text item= MB_DT1 Text item= MB_DT2 Text item= MB_BTN Switch item= MB_CL16 Switch item= MB_CL17 Switch item= MB_CL18 Switch item= MB_LED Text item= MB_INPT2 Text item= MB_INPT3 Text item= MB_INPT4 Setpoint item= MB_HOLD5 minValue=0 maxValue=50 step=1 Setpoint item= MB_HOLD6 minValue=0 maxValue=500 step=10 Setpoint item= MB_HOLD7 minValue=0 maxValue=500 step=100 } Первый фрейм содержит группу FF_Modbus, он отобразит все элементы, входящие в неё.Во втором фрейме каждый элемент имеет индивидуальные настройки интерфейса. В настройках указан тип виджета, связь с элементом и в некоторых случаях дополнительные параметры. Ознакомиться с принципами построения интерфейса OpenHAB можно в этом описании.76ee63e6bea4436e9b7f6d43fa6bf397.JPG

Попробуем протестировать созданную конфигурацию на симуляторе.

Скачаем симулятор RSsim 8.19 со страницы загрузки и распакуем его в папку C:\arduino. У программы есть интересная особенность, она бесплатна, и доступны её исходные коды, но при этом она требует регистрации. В инструкции сказано, что для регистрации нужно открыть окно About MOD_RSsim, нажать кнопку «Register», в поле registration name ввести «Completely Free», а в поле registration key »66840713».

Запускаем симулятор, выполняем регистрацию, в поле Port выбираем MODBUS RS-232, нажимаем кнопку 282ecb8835354a81a095a4a0fd4ca948.JPG, в диалоге настроек последовательного порта указываем второй порт виртуальной пары (например, COM8), скорость 9600, 1 стоповый бит, нет контроля чётности.

b8efeef42c574d8da251c198b456d6f1.JPG

a7b7470e83f54009ac7d6183daa2a3f9.JPG

Запускаем OpenHAB и открываем веб-интерфейс, щёлкаем по переключателям и смотрим, как изменяются значения в таблице Coil симулятора, затем открываем в симуляторе таблицу Digital Inputs, изменяем значения в регистрах с адресами 10001–10004 и контролируем изменение состояния контактов в веб-интерфейсе. После этого открываем таблицу Analog Inputs, вводим значения в регистры 30003–30005 и контролируем изменение значений в полях INPT2- INPT4. И в завершении задаём значения в полях HOLD5-HOLD7 и проверяем их соответствие в регистрах 40006–40008 симулятора. Вы уже обратили внимание, что в симуляторе использована логическая адресация. Для того, что бы окончательно не запутаться в регистрах, адресах и элементах используйте ранее приведённую таблицу.

На первый взгляд всё получилось, но если внимательно посмотреть на консоль OpenHAB заметно, что при каждом опросе контроллера, плагин отправляет в шину событие, даже если ничего не изменилось. Похоже, что для решения этой проблемы придётся изучить и доработать плагин.

Описание решения Краткую информацию по архитектуре плагина OpenHAB можно посмотреть здесь.Вопросы настройки среды разработки для OpenHAB отражены в этом руководстве.В процессе работы изменения коснулись двух файлов ModbusGenericBindingProvider.java и ModbusBinding.java.

ModbusGenericBindingProvider содержит вложенный класс ModbusBindingConfig который хранит конфигурацию элемента, создадим в нём механизм сохранения текущего состояния.

Добавим в этот класс переменную

private State mb_itemState = UnDefType.NULL; Исправим код функции State getItemState () { return mb_itemState; } И добавим функцию void setItemState (State state) { mb_itemState = state; } Класс ModbusBinding содержит два метода: protected void internalUpdateItem (String slaveName, InputRegister[] registers, String itemName) Который отправляет событие обновления в шину OpenHAB для данных типа holding. protected void internalUpdateItem (String slaveName, BitVector coils, String itemName) Который отправляет событие обновления в шину OpenHAB для данных типа coil.Эти методы вызываются каждый раз после опроса ведомого устройства. Поправим их код таким образом, чтобы отправлять событие только в том случае, если данные изменились.

protected void internalUpdateItem (String slaveName, InputRegister[] registers, String itemName) { for (ModbusBindingProvider provider: providers) { if (! provider.providesBindingFor (itemName)) { continue; } ModbusBindingConfig config = provider.getConfig (itemName); if (! config.slaveName.equals (slaveName)) { continue; } String slaveValueType = modbusSlaves.get (slaveName).getValueType (); double rawDataMultiplier = modbusSlaves.get (slaveName).getRawDataMultiplier (); State newState = extractStateFromRegisters (registers, config.readRegister, slaveValueType); /* receive data manipulation */ if (config.getItem () instanceof SwitchItem) { newState = newState.equals (DecimalType.ZERO) ? OnOffType.OFF: OnOffType.ON; } if ((rawDataMultiplier!= 1) && (config.getItem () instanceof NumberItem)) { double tmpValue = (double)((DecimalType)newState).doubleValue () * rawDataMultiplier; newState = new DecimalType (String.valueOf (tmpValue)); } State currentState = config.getItemState (); if (! newState.equals (currentState)) { eventPublisher.postUpdate (itemName, newState); config.setItemState (newState); //!!! } } } protected void internalUpdateItem (String slaveName, BitVector coils, String itemName) { for (ModbusBindingProvider provider: providers) { if (provider.providesBindingFor (itemName)) { ModbusBindingConfig config = provider.getConfig (itemName); if (config.slaveName.equals (slaveName)) { boolean state = coils.getBit (config.readRegister); State currentState = provider.getConfig (itemName).getItemState (); State newState = provider.getConfig (itemName).translateBoolean2State (state); if (! newState.equals (currentState)) { eventPublisher.postUpdate (itemName, newState); config.setItemState (newState); //!!! } } } } } Исправленный плагин вместе с исходными кодами размещён в этом репозитории.Останавливаем OpenHAB, скачиваем и копируем org.openhab.binding.modbus-1.6.2.jar в папку C:\openhab\addons. Запускаем C:\openhab\start.bat, открываем веб-интерфейс и проверяем работу еще раз. Теперь всё хорошо, события появляются только тогда, когда изменяется значение соответствующего регистра.Осталось самое интересное — проверить взаимодействие OpenHAB непосредственно с контроллером из предыдущей статьи.Подключаем USB кабель контроллера к компьютеру, смотрим, на какой порт встал переходник (например, COM6), останавливаем OpenHAB, открываем в конфигураторе файл openhab_default.cfg, в разделе Modbus Binding в параметрах связи для каждой группы регистров исправляем номер порта (например, modbus: serial.slave1.connection=COM6). Сохраняем файл, запускаем OpenHAB и открываем веб-интерфейс. Попробуем поменять значение в полях HOLD5…HOLD7 и СL16…СL18, при этом должно поменяться значение в соответствующем поле INPT2…INPT4 и DT0…DT2, затем нажмём на кнопку макета, при этом должно поменяться значение в поле BTN, щёлкнем по полю LED, при этом должен загореться или потухнуть светодиод.

Что мы получили в результате нашей работы:1. состыковали modbus устройство с платформой OpenHAB;2. познакомились с принципами построения интерфейса в OpenHAB;3. познакомились с внутренней структурой плагина, это позволило исправить неточность в его работе.

Выводы: На основе контроллера Arduino и платформы OpenHAB не трудно создать программно-аппаратное решение для автоматизации, например в системе Умный дом. Для дальнейших практических экспериментов попробуем определить основной функционал и требования к контроллеру и системе в целом, для обсуждения этого вопроса создана страничка открытого проекта vk.com/myremoter.

© Habrahabr.ru