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, запускаем Setup из меню программы, смотрим, для каких последовательных портов создана виртуальная пара (у меня это 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 нам поможет следующая таблица.



    Настало время отобразить наши элементы в интерфейсе. Откроем в конфигураторе файл 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, нажимаем кнопку , в диалоге настроек последовательного порта указываем второй порт виртуальной пары (например, COM8), скорость 9600, 1 стоповый бит, нет контроля чётности.





    Запускаем 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.
    • +16
    • 48.8k
    • 4
    Share post

    Similar posts

    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More
    Ads

    Comments 4

      0
      Я полгода назад делал аналогичный эксперимент. Проблема была в том, что OpenHAB переставал опрашивать датчики на Arduino по ModBus TCP. У Вас нет таких проблем?
        0
        В статье описана связь с контроллером через последовательный порт (переходник с USB на RS232), соответственно использован протокол Modbus RTU. На первый взгляд такое соединение работает достаточно надёжно.
        Так как проект OpenHAB развивается достаточно быстро, советую поэкспериментировать с Modbus TCP ещё раз, если что-то не получится — пишите, попробуем разобраться вместе.
          0
          Возможно, нормальной работе мешала описанная в этой статье проблема с плагином.
        0
        Ещё один вариант взаимодействия описан в этой статье: habrahabr.ru/post/250833/

        Only users with full accounts can post comments. Log in, please.