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.

ссылка на оригинал статьи http://habrahabr.ru/post/252555/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *