В предыдущей статье мы познакомились с промышленным стандартом Modbus и встроили его поддержку в Arduino, осталось состыковать устройство с платформой OpenHAB.
В этот раз мы узнаем, как настроить плагин и интерфейс OpenHAB для работы с устройством, основы адресации и отладки протокола Modbus. В работе представлен эксперимент с исходным кодом плагина, а на страничке vk.com/myremoter можно обсудить открытый контроллер умного дома, который мы будем использовать в следующих экспериментах.
Но, давайте ещё раз посмотрим, какие преимущества даст нам применение стандарта Modbus?
Современный дом — сложное инженерное сооружение, где управление освещением не самая главная функция. Кроме датчиков в доме устанавливают системы кондиционирования и вентиляции, управления отоплением, дренажными насосами и скважинами. Такие задачи можно поручить специальному или промышленному контроллеру, в этом случае протокол Modbus поможет объединить все инженерные системы в единую сеть, а простой и недорогой контроллер, работающий на одной с ними шине, добавит дополнительный контроль и функционал, сэкономив немало средств. В пользу этого низкие требования к оборудованию, открытость стандарта, массовость его применения, хотя, быть может, основной секрет популярности Modbus его гибкость при стыковке программ и оборудования.
Ну что же, пора приступать к работе.
Затем установим плагин Modbus Tcp Binding который обеспечит взаимодействие OpenHAB с modbus устройствами. Откроем страницу загрузки, скачаем Addons, распакуем org.openhab.binding.modbus-1.6.2.jar в папку C:\openhab\addons.
После этого настроим связь плагина с устройством, для этого запустим конфигуратор OpenHAB и откроем файл openhab_default.cfg. Найдём раздел Modbus Binding и добавим в конец этого раздела следующую информацию, затем сохраним файл.
Настройки содержат 4 группы адресов сопоставленных с регистрами устройства. В каждой группе указан номер последовательного порта, modbus адрес контроллера, modbus адрес первого в группе регистра, количество регистров в группе и тип этих регистров. Группы адресов станут связующим звеном между элементами OpenHAB и устройством.
Теперь настроим связь OpenHAB с регистрами устройства. Откроем в конфигураторе файл demo.items и добавим в конец этого файла следующий код:
В первой строке определена группа FF_Modbus которая объединит добавляемые элементы. Каждый элемент задан его типом, названием, форматом текстовой надписи, списком групп в которых он состоит и настройками связи с устройством. Мы использовали элементы трёх типов – Contact, Switch, Number, а в настройках связи указали тип (modbus), имя одной из групп заданных в настройках плагина (например, slave1) и порядковый номер регистра в этой группе.
Наглядно представить взаимосвязь между регистрами контроллера, обычными и логическими адресами Modbus, группами регистров в настройках плагина и элементами OpenHAB нам поможет следующая таблица.

Настало время отобразить наши элементы в интерфейсе. Откроем в конфигураторе файл demo.sitemap и добавим в него описание двух фреймов:
Первый фрейм содержит группу FF_Modbus, он отобразит все элементы, входящие в неё.
Во втором фрейме каждый элемент имеет индивидуальные настройки интерфейса. В настройках указан тип виджета, связь с элементом и в некоторых случаях дополнительные параметры. Ознакомиться с принципами построения интерфейса OpenHAB можно в этом описании.

Попробуем протестировать созданную конфигурацию на симуляторе.
Скачаем симулятор RSsim 8.19 со страницы загрузки и распакуем его в папку C:\arduino. У программы есть интересная особенность, она бесплатна, и доступны её исходные коды, но при этом она требует регистрации. В инструкции сказано, что для регистрации нужно открыть окно About MOD_RSsim, нажать кнопку «Register», в поле registration name ввести “Completely Free”, а в поле registration key “66840713”.
Запускаем симулятор, выполняем регистрацию, в поле Port выбираем MODBUS RS-232, нажимаем кнопку
, в диалоге настроек последовательного порта указываем второй порт виртуальной пары (например, COM8), скорость 9600, 1 стоповый бит, нет контроля чётности.


Запускаем OpenHAB и открываем веб-интерфейс, щёлкаем по переключателям и смотрим, как изменяются значения в таблице Coil симулятора, затем открываем в симуляторе таблицу Digital Inputs, изменяем значения в регистрах с адресами 10001-10004 и контролируем изменение состояния контактов в веб-интерфейсе. После этого открываем таблицу Analog Inputs, вводим значения в регистры 30003-30005 и контролируем изменение значений в полях INPT2- INPT4. И в завершении задаём значения в полях HOLD5-HOLD7 и проверяем их соответствие в регистрах 40006-40008 симулятора. Вы уже обратили внимание, что в симуляторе использована логическая адресация. Для того, что бы окончательно не запутаться в регистрах, адресах и элементах используйте ранее приведённую таблицу.
На первый взгляд всё получилось, но если внимательно посмотреть на консоль OpenHAB заметно, что при каждом опросе контроллера, плагин отправляет в шину событие, даже если ничего не изменилось. Похоже, что для решения этой проблемы придётся изучить и доработать плагин.
Исправленный плагин вместе с исходными кодами размещён в этом репозитории.
Останавливаем 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.
В этот раз мы узнаем, как настроить плагин и интерфейс 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, запускаем
Setup из меню программы, смотрим, для каких последовательных портов создана виртуальная пара (у меня это COM7 + COM8). Используем их для связи OpenHAB и симулятора.
Запустим OpenHAB, выполнив C:\openhab\start.bat и откроем веб-интерфейс по ссылке localhost:8080/openhab.app?sitemap=demo
Теперь качаем и устанавливаем com0com, запускаем
Затем установим плагин 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 нам поможет следующая таблица.
Настало время отобразить наши элементы в интерфейсе. Откроем в конфигураторе файл 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 можно в этом описании.
Попробуем протестировать созданную конфигурацию на симуляторе.
Скачаем симулятор RSsim 8.19 со страницы загрузки и распакуем его в папку C:\arduino. У программы есть интересная особенность, она бесплатна, и доступны её исходные коды, но при этом она требует регистрации. В инструкции сказано, что для регистрации нужно открыть окно About MOD_RSsim, нажать кнопку «Register», в поле registration name ввести “Completely Free”, а в поле registration key “66840713”.
Запускаем симулятор, выполняем регистрацию, в поле Port выбираем MODBUS RS-232, нажимаем кнопку
Запускаем 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 который хранит конфигурацию элемента, создадим в нём механизм сохранения текущего состояния.
Добавим в этот класс переменную
Исправим код функции
И добавим функцию
Класс ModbusBinding содержит два метода:
Эти методы вызываются каждый раз после опроса ведомого устройства. Поправим их код таким образом, чтобы отправлять событие только в том случае, если данные изменились.
Вопросы настройки среды разработки для 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 содержит два метода:
Который отправляет событие обновления в шину OpenHAB для данных типа holding.protected void internalUpdateItem(String slaveName, InputRegister[] registers, String itemName)
Который отправляет событие обновления в шину OpenHAB для данных типа coil.protected void internalUpdateItem(String slaveName, BitVector coils, String itemName)
Эти методы вызываются каждый раз после опроса ведомого устройства. Поправим их код таким образом, чтобы отправлять событие только в том случае, если данные изменились.
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.