OpenHAB - интеграция с Beckhoff, первые шаги по освоению

Обсуждение статей, технологий домашней автоматизации, программных и аппаратных решений
Ответить
Selecta
Сообщения: 31
Зарегистрирован: 26 сен 2015, 12:38

OpenHAB - интеграция с Beckhoff, первые шаги по освоению

Сообщение Selecta » 16 окт 2015, 02:26

По просьбе в личных сообщениях, делюсь своими настройками для интеграции Beckhoff с системой "умного дома" OpenHAB. Интересующихся общими принципами функционирования OpenHAB отправляю к краткому обзору на Хабре - http://habrahabr.ru/post/232969/. От себя отмечу, что OpenHab полностью удовлетворил мои запросы по программированию и визуализации УД - масса binding'ов для любого оборудования, простой язык правил и скриптов, неплохие средства визуализации, стабильная работа даже под Windows (у меня крутится под 10) - в общем, все что нужно для непритязательного старта. В стандартном наборе - binding'и для связи с более чем 50 системами (от Z-Wave, KNX и EnOcean до проекторов Epson и кондиционеров Daikin). То что уже работает у меня - мультирум через Softsqueeze (стандартный байндинг Squeezebox), голосовое управление с андроид-планшета, анализ голосовых команд (пока ограничено "поставь Гребенщикова в спальне", "поставь джаз в гостиной", "сделай свет ярче на кухне" и т.п.), голосовая обратная связь через Yandex TTS, интеграция с гугль-календарем и сервисами погоды. Если интересно - в последующих сообщениях расскажу подробнее с примерами кода.

Ну а пока про то, как подружить его с Beckhoff. Структура ПЛК, похоже, препятствует прямому обращению по Modbus к битовым регистрам (coils) - по крайней мере, обратиться к ним у меня не получилось ни из OpenHAB, ни из внешних программ типа Modbus Poll - при обращении "read coil", "write coil" - сообщение об ошибке "неправильный адрес" в ответ. Если кто-то знает, как это победить - буду признателен за совет. Возможно, поможет настройка в KS2000. Ну а пока что я научился только читать-писать пословно в область памяти с адреса 16384 (0х4000) - это позволяет мне обмениваться данными с OpenHAB, хотя и не дает возможности напрямую взаимодействовать с аппаратными входами-выходами устройства. Приходится прибегать к программным костылям, но это проблема не самая страшная.

Итак, конфиг OpenHAB (не забудьте скопировать в папку addons соответствующий байндинг для Modbus - org.openhab.binding.modbus-1.7.1):

Код: Выделить всё

modbus:tcp.slave1.connection=192.168.0.108:502
modbus:tcp.slave1.id=1
modbus:tcp.slave1.start=0
modbus:tcp.slave1.length=16
modbus:tcp.slave1.type=holding

modbus:tcp.slave2.connection=192.168.0.108:502
modbus:tcp.slave2.id=1
modbus:tcp.slave2.start=16384
modbus:tcp.slave2.length=16
modbus:tcp.slave2.type=holding
slave1 у меня умеет читать из Beckhoff, а slave2 - читать и писать

описание тестовых айтемов (для отслеживания и управления выходами Beckhoff):

Код: Выделить всё

Switch Beckhoff_Input10	(gModbus)	{ modbus="slave1:0"} 
Switch Beckhoff_Input11	(gModbus)	{ modbus="slave1:1"}

Switch Beckhoff_Input20	(gModbus)	{ modbus="slave2:0"} 
Switch Beckhoff_Input21	(gModbus)	{ modbus="slave2:1"}
и отображение их на сайтмэпе:

Код: Выделить всё

	Frame {
		Group item=gModbus label="Modbus"
	}
Далее, описания переменных для "общения" с OpenHAB в программе ПЛК:

Код: Выделить всё

VAR_GLOBAL
	OH_I1		AT %QB128:	INT;       //  "slave1:0"
	OH_I2		AT %QB130:	INT;	     //  "slave1:1"
         OH_O1		AT %MB0:       INT;	     //  "slave2:0"
         OH_O2		AT %MB2:       INT;          //  "slave2:1"
	IN_E_K1		AT %IX0.0:	BOOL;		// кнопка аппаратного входа
	IN_E_K2		AT %IX0.1:	BOOL;		// кнопка аппаратного входа
	OUT_E_L1 	AT %QX0.0:	BOOL;	// выход на реле (лампочка)
	OUT_E_L2	AT %QX0.1:	BOOL;		// выход на реле (вентилятор)
END_VAR
Для экспериментов была взята программа из темы про "Элементы умного дома на Beckhoff", включающая лампочку и вентилятор. Логика работы простая - короткое нажатие в темноте включает лампочку, длинное - включает лампочку и вентилятор, короткое нажатие при включенной лампочке и/или вентиляторе выключает лампочку, а вентилятор остается включенным на заданный период времени, длинное нажатие при включенной лампочке и вентиляторе выключает сразу и то, и то.

Без участия OpenHAB все было достаточно просто - два таймера, каждый со своей логикой в ПЛК, и все работало как часы. Но подключив все это хозяйство к OpenHAB, сразу возникло желание не только видеть в OpenHAB состояние лампочки и вентилятора, но и иметь возможность независимо включать и выключать оба прибора из программной оболочки, параллельно с аппаратной кнопкой. Что естественно привело к конфликту приоритетов - что считать более главным - нажатия кнопки или команды OpenHAB.

В конечном итоге после двух вечеров экспериментов решение приняло такой вид:

Функциональный блок кнопки без таймера (нужно для принудительного включения-выключения):

Код: Выделить всё

FUNCTION_BLOCK SM_BUTT
VAR_INPUT
	IN: BOOL;
END_VAR
VAR_OUTPUT
	Q:BOOL := FALSE;
END_VAR
VAR
	MEM:BOOL := FALSE;
END_VAR


IF IN AND NOT MEM THEN
	Q:= NOT Q;
END_IF

	MEM := IN;
Функциональный блок кнопки с таймерами:

Код: Выделить всё

FUNCTION_BLOCK SM_BUTT_TIMER
VAR_INPUT
	IN: BOOL;		(* вход за которым следим *)
	TC: TIME;		(* время длинного нажатия  *)
	TC2: TIME;		(* время работы вентилятора *)
END_VAR
VAR_OUTPUT
	Q1: BOOL := FALSE;		(* состояние лампочки *)
	Q2: BOOL := FALSE;		(* состояние вентилятора  *)
END_VAR
VAR
	TX: TON;
	TX2: TON;
	MEM1, MEM2, MEM3: BOOL;
END_VAR

TX (IN := IN, PT := TC); 		(*  отправляем данные в таймеры *)
TX2(IN := NOT Q1, PT:=TC2);

IF IN AND NOT MEM1  THEN     	(* если нажали аппаратную кнопку *)
	Q1 := NOT Q1;			(* сразу меняем состояние лампочки *)
END_IF

IF TX.Q AND NOT MEM2  THEN		(* сигнал таймера1 когда лампочка горит *)
	Q2 := Q1;					(*  состояние вентилятора = состоянию лампочки *)
END_IF

IF TX2.Q AND  NOT MEM3   THEN			(* сигнал от таймера 2 *)
	IF NOT Q1 THEN					(* если лампочка выключена  *)
		Q2 := FALSE;					(* выключить и вентилятор *)
	END_IF
END_IF

MEM1 := IN;
MEM2 := TX.Q;
MEM3 := TX2.Q;

Ну и основная программа:

Код: Выделить всё

PROGRAM MAIN
VAR
	BUTT_E_B1:SM_BUTT;
	BUTT_E_B2:SM_BUTT_TIMER;
	LampState , FanState: BOOL := FALSE;
END_VAR


IF NOT (INT_TO_BOOL(OH_O1) = LampState) THEN    			(* Если поменялось состояние лампочки в OpenHAB *)
		BUTT_E_B2 (IN:=TRUE, TC:=t#1s, TC2:=t#10s);    	(*  "нажать" на аппаратную кнопку программно *)
	ELSE
		BUTT_E_B2 (IN:=IN_E_K1, TC:=t#1s, TC2:=t#10s);	(* иначе запустить обычную проверку нажатия *)
END_IF

OUT_E_L1 := BUTT_E_B2.Q1;							(* переключить выход лампочки *)		
OH_O1 := BOOL_TO_INT(OUT_E_L1);						(* и сохранить значение в OpenHAB *)
LampState := OUT_E_L1;

IF NOT (INT_TO_BOOL(OH_O2) = FanState) THEN			(* если поменялось состояние вентилятора в OpenHAB *)
		FanState := INT_TO_BOOL(OH_O2);				(* переключить вентилятор *)
	ELSE
		FanState := BUTT_E_B2.Q2;					(* иначе присвоить вентилятору состояние выхода по значению кнопки *)
END_IF

OUT_E_L2 := FanState;
OH_O2 := BOOL_TO_INT(OUT_E_L2);

Сильно не пинайте - понимаю, что код корявый, и изящнее было бы использовать триггеры, но поскольку это моя первая программа для ПЛК, пока что не хватает опыта. В будущем перепишу покрасивее, и буду признателен за советы.

Но в таком виде все работает отлично - аппаратная кнопка полностью выполняет свою функцию, все включения-выключения лампочки и вентилятора видны в интерфейсе OpenHAB, и принудительное переключение элементов интерфейса мышкой вызывает соответствующую реакцию выходов Beckhoff.

Как-то так. Если будут вопросы - задавайте. Ну и буду рад вашим собственным описаниям интеграции устройств с OpenHAB и прикольных сценариев для него, так как только начинаю его осваивать. Но подчеркну еще раз - система полностью удовлетворяет мои немудреные потребности. Я не представляю задачи по домашней автоматизации, которую с ее помощью невозможно было бы решить. Недостаток - отсутствие нормальной документации, но активное сообщество частично это компенсирует. Любую задачу или проблему кто-то уже решал до тебя, нужно только найти это обсуждение в гугле.

scorp309
Сообщения: 35
Зарегистрирован: 12 окт 2011, 11:21

Re: OpenHAB - интеграция с Beckhoff, первые шаги по освоению

Сообщение scorp309 » 20 окт 2015, 22:43

Не получается заставить работать openhab и bc9000 совместно.
Что сделал:

Код: Выделить всё

openhab_default.cfg

modbus:poll=500
modbus:slave1.host=192.168.121.9
modbus:slave1.type=holding
modbus:slave1.id=1
modbus:slave1.start=16384
modbus:slave1.length=16

Код: Выделить всё

demo.items

Group FF_Modbus		"Modbus"					(All)
Switch Beckhoff_Input10				"CL10"			(FF_Modbus){modbus="slave1:0"}
Switch Beckhoff_Input11				"CL11"			(FF_Modbus){modbus="slave1:1"}
Switch Beckhoff_Input12				"CL12"			(FF_Modbus){modbus="slave1:2"}
Switch Beckhoff_Input13				"CL13"			(FF_Modbus){modbus="slave1:3"}
Switch Beckhoff_Input14				"CL14"			(FF_Modbus){modbus="slave1:4"}
Switch Beckhoff_Input15				"CL15"			(FF_Modbus){modbus="slave1:5"}
Switch Beckhoff_Input16				"CL16"			(FF_Modbus){modbus="slave1:6"}
Switch Beckhoff_Input17				"CL17"			(FF_Modbus){modbus="slave1:7"}
Switch Beckhoff_Input18				"CL18"			(FF_Modbus){modbus="slave1:8"}

Код: Выделить всё

demo.sitemap

	Frame label="Test" {
		Text label=Test_Frame icon="attic" {
		Frame {
	Switch item= Beckhoff_Input10
	Switch item= Beckhoff_Input11
	Switch item= Beckhoff_Input12
	Switch item= Beckhoff_Input13
	Switch item= Beckhoff_Input14
	Switch item= Beckhoff_Input15
	Switch item= Beckhoff_Input16
	Switch item= Beckhoff_Input17
	Switch item= Beckhoff_Input18
					}
19 кнопок сделал для отлова адресации, на случай если неправильно что то где то прописал.

В bc9000 программа следующая

Код: Выделить всё

PROGRAM MAIN
VAR
	BUTT_MB1		:	SM_BUTT;
	LampState1: BOOL := FALSE;
END_VAR

IF NOT (INT_TO_BOOL(OH_O1) = LampState1) THEN
		BUTT_MB1 (IN:=TRUE);
	ELSE
		BUTT_MB1 (IN:=IN_MB1);
END_IF

OUT_MB1_L:=BUTT_MB1.Q;
OH_O1:= BOOL_TO_INT(OUT_MB1_L);
LampState1 := OUT_MB1_L;

Код: Выделить всё

VAR_GLOBAL
	OH_O1				AT %MB0:	INT;	(*slave1:0*)
END_VAR

Код: Выделить всё

VAR_GLOBAL
	IN_MB1				AT %IX0.2:	BOOL;

	OUT_MB1_L			AT %QX0.1:	BOOL;
END_VAR
С кнопки работает - лампа зажигается, но в вэб-интерфейсе всё глухо, такое ощущение, что связи с контроллером нету. C modbus pool при ручном вводе значений в ячейку памяти тоже всё работает.
Где я накосячил?

Selecta
Сообщения: 31
Зарегистрирован: 26 сен 2015, 12:38

Re: OpenHAB - интеграция с Beckhoff, первые шаги по освоению

Сообщение Selecta » 21 окт 2015, 10:36

modbus:slave1.host=192.168.121.9
Где я накосячил?
Скорее всего - в описании modbus. Потому что правильное ключевое слово connection, а не host. Посмотрите в первом сообщении темы.

А вообще - есть смысл смотреть лог-файл при инициализации openhab. Все байндинги там отписываются и можно найти проблему.

scorp309
Сообщения: 35
Зарегистрирован: 12 окт 2011, 11:21

Re: OpenHAB - интеграция с Beckhoff, первые шаги по освоению

Сообщение scorp309 » 21 окт 2015, 12:47

Host было в дефолтном конфиге openhab. Я только расскомментировал строку и вписал IP

В логах ничего не пишет вообще упоминается только в openhab.log

Код: Выделить всё

[INFO ] [.service.AbstractActiveService] - Modbus Polling Service has been started
Да у меня openhab на винде 7. Надо наверно линуксовую машину организавать на попробовать.

Selecta
Сообщения: 31
Зарегистрирован: 26 сен 2015, 12:38

Re: OpenHAB - интеграция с Beckhoff, первые шаги по освоению

Сообщение Selecta » 21 окт 2015, 22:15

Host было в дефолтном конфиге openhab
Я тоже на эти грабли наступал. Кроме дефолтного конфига нужно читать описания байндингов. В конфиге есть устаревшие моменты, которые есть только в описании и в обсуждениях на гугльгруппах.
Да у меня openhab на винде 7. Надо наверно линуксовую машину организавать на попробовать.
У меня работает под Windows 10 без проблем.

scorp309
Сообщения: 35
Зарегистрирован: 12 окт 2011, 11:21

Re: OpenHAB - интеграция с Beckhoff, первые шаги по освоению

Сообщение scorp309 » 21 окт 2015, 23:42

Как я и ожидал - ошибка идиотская :oops:
  • modbus:tcp.slave1.connection=192.168.121.9
    modbus:tcp.slave1.type=holding
    modbus:tcp.slave1.id=1
    modbus:tcp.slave1.start=16384
    modbus:tcp.slave1.length=16

scorp309
Сообщения: 35
Зарегистрирован: 12 окт 2011, 11:21

Re: OpenHAB - интеграция с Beckhoff, первые шаги по освоению

Сообщение scorp309 » 23 окт 2015, 22:34

Немного повозился с кодом. Смущала монструозность программы. На выходе получилось, что переменные LampState/FanState и не нужны, вместо них можно использовать состояние выходов. И условие IF из основной программы можно перенести в функцию кнопки.
Переменные для OpenHAB у меня прописаны данным образом

Код: Выделить всё

H2_R1_L				AT %MB0:	INT;
И работает это только с чётными значениями почему то, если прописать MB1 - ругается Invalid type INT at address: %MB1
Кто-нибудь знает почему?

Поехали по коду

Код: Выделить всё

FUNCTION_BLOCK SM_BUTT_OH	(*ОБЫЧНАЯ КНОПКА *)
VAR_INPUT
	IN: BOOL;					(*ВХОД ЗА КОТОРЫМ СЛЕДИМ*)
	MB: INT;						(*ЗНАЧЕНИЕ В ПАМЯТИ ДЛЯ OPENHAB*)
	OUT: BOOL;					(*СОСТОЯНИЕ ВЫХОДА*)
END_VAR
VAR
	MEM : BOOL := FALSE;			(*ВНУТРЕННЯЯ ПЕРЕМЕННАЯ ДЛЯ ХРАНЕНИЯ СОСТОЯНИЯ ВХОДА *)
END_VAR
VAR_OUTPUT
	Q: BOOL:=FALSE;				(*СОСТОЯНИЕ ВЫХОДА НА ЛАМПОЧКУ*)
END_VAR
---------------------------------
IF NOT(INT_TO_BOOL(MB) = OUT) THEN   (*УСЛОВИЕ IF, КОТОРОЕ ПЕРЕНЕСЛИ ИЗ ОСНОВНОЙ ПРОГРАММЫ*)
		Q:= NOT Q;
	ELSE
		IF IN AND NOT MEM THEN (*ПОЙМАЛИ НАЖАТИЕ НА КНОПКУ*)
			Q:= NOT Q;			(*МЕНЯЕМ СОСТОЯНИЕ ВЫХОДА НА ПРОТИВОПОЛОЖНОЕ*)
		END_IF
END_IF
		MEM := IN; (*ЗАПОМИНАЕМ ТЕКУЩЕЕ СОСТОЯНИЕ ВХОДА*)
В результате в основной программе будем иметь:

Код: Выделить всё

PROGRAM MAIN
VAR
	BUTT_H2_R1	:	SM_BUTT_OH;
	BUTT_H2_R2	:	SM_BUTT_OH;
END_VAR
---------------------------------
BUTT_H2_R1 (IN:=IN_H2_R1 OR  IN_H2_R2, OUT:=OUT_H2_R1_L, MB:=H2_R1_L);	(*ВАРИАНТ С ПРОХОДНЫМ ВЫКЛЮЧАТЕЛЕМ*)
	OUT_H2_R1_L:=BUTT_H2_R1.Q;
	H2_R1_L:= BOOL_TO_INT(OUT_H2_R1_L);
	
BUTT_H2_R2 (IN:=IN_H2_R3, OUT:=OUT_H2_R2_L, MB:=H2_R2_L);				(*ОБЫЧНАЯ ОРДИНАРНАЯ КНОПКА*)
	OUT_H2_R2_L:=BUTT_H2_R2.Q;
	H2_R2_L:= BOOL_TO_INT(OUT_H2_R2_L);
Пояснение небольшое
  • IN_H2_R1, IN_H2_R2 и IN_H2_R3 - входные контакты
    OUT_H2_R1_L и OUT_H2_R2_L - выходы
    H2_R1_L и H2_R2_L - переменные в который пишется состояние выходов и с которыми взаимодействует OpenHAB
Конструктивная критика приветствуется. Я не программист ни разу, так что написал как смог :D

Дальше в планах разобраться с таймером (у меня по длительному нажатию кнопки в прихожей выключался весь свет в квартире)

Selecta
Сообщения: 31
Зарегистрирован: 26 сен 2015, 12:38

Re: OpenHAB - интеграция с Beckhoff, первые шаги по освоению

Сообщение Selecta » 24 окт 2015, 01:57

И работает это только с чётными значениями почему то, если прописать MB1 - ругается Invalid type INT at address: %MB1
Кто-нибудь знает почему?
Потому что INT занимает два байта.

empenoso
Сообщения: 869
Зарегистрирован: 11 ноя 2015, 08:03
Откуда: Пермь

Re: OpenHAB - интеграция с Beckhoff, первые шаги по освоению

Сообщение empenoso » 27 авг 2016, 22:39

В чем-то есть принципиальное отличие между ПЛК в частности Beckhoff (или ОВЕН) и контроллера MegaD для применения в домашней автоматизации?

d.v.ermakov
Сообщения: 556
Зарегистрирован: 29 май 2015, 21:23
Откуда: Екатеринбург, Нижний Тагил

Re: OpenHAB - интеграция с Beckhoff, первые шаги по освоению

Сообщение d.v.ermakov » 28 авг 2016, 06:01

У Меги прошивка открытая (и есть 1wire,dht,ir поэтому). И дешевле она.

flighttothemoon
Сообщения: 101
Зарегистрирован: 27 мар 2011, 02:15

Re: OpenHAB - интеграция с Beckhoff, первые шаги по освоению

Сообщение flighttothemoon » 07 дек 2016, 03:05

А не логичнее ли связать beckhoff и openhab через TCP Binding?

Pagan
Сообщения: 17
Зарегистрирован: 25 авг 2013, 16:50

Re: OpenHAB - интеграция с Beckhoff, первые шаги по освоению

Сообщение Pagan » 25 янв 2017, 22:36

Господа, а не подскажете случаем как настроить библиотечные блоки modbus TCP server на TwinCAT? Для связи с ОН. У меня контролёр СХ9000.

scorp309
Сообщения: 35
Зарегистрирован: 12 окт 2011, 11:21

Re: OpenHAB - интеграция с Beckhoff, первые шаги по освоению

Сообщение scorp309 » 26 окт 2017, 13:36

2 года пролетели как неделя :roll: Beckhoff работает и не жужжит, а вот OpenHab пару раз ломался при обновлении. Стал вносить изменения небольшие в электрическую схему квартиры и понадобилось опять углубляться в настройку опенхаба и бехкофа.
По-человечески работу с таймером настроить не получилось (даже привлечение Си программиста не помогло), точнее оно работало конечно, но немного не так как задумывалось. В принципе жить можно и было оставлено так. Потому свой корявый код не решился выставлять на публичное обозрение.

В общем вернулся к настройке и даже есть что показать :D
В программе глаза мозолили постоянные преобразования INT-to-BOOL и обратно и хотелось всё-таки, чтобы корректно работало длительное нажатие. А тут ещё подкатила задача отрабатывать двойной клик! Ну и стал ковырять настройки OpenHab и программу Beckhoff.

Откатился к версии программы, которую написал на основе исходников Уважаемого Ali (там всё работало корректно и исключительно на BOOL переменных). И стал прикручивать к этому коду OpenHab2. В общем вылезла такая закономерность - опенхаб читает ячейки памяти с контроллера целым словом и корректно соотносит биты в этом слове с переключателями в интерфейсе, но при записи перезаписывает слово целиком и затирает состояния остальных ячеек. Пример: слово - это 2 байта или 16 бит в которых записывается 0 или 1 в зависимости от состояния выхода (вкл/выкл). Для визуализации

Код: Выделить всё

0000 0000  0000 0000
Нулевой бит означает состояние выхода на люстру гостиной к примеру, а первый бит связан с люстрой в спальне. Тогда если свет включен в обеих комнатах, то получим

Код: Выделить всё

0000 0000 0000 0011
OpenHab это нормально прочитает и отобразит в интерфейсе, что свет включен в обеих комнатах. Но если мы через интерфейс выключим свет в гостиной, то опенхаб перезапишет всё слово нулями и свет погаснет и в спальне. Кароч неудобно :shock:

Победить опенхаб, чтобы он записывал по-битово не получилось и было принято решение зайти с тылу. В программе beckhoff-a присвоил значения не битам в слове, а нулевым битам в разных словах

Код: Выделить всё

Было
	H2_R1_L				AT %MX0.0:	BOOL := FALSE;
	H2_R2_L				AT %MX0.1:	BOOL := FALSE;

Стало
	H2_R1_L				AT %MX0.0:	BOOL := FALSE;
	H2_R2_L				AT %MX2.0:	BOOL := FALSE;
Единственная неудобность - пришлось для каждого слова прописывать настройки modbus в OpenHab

Код: Выделить всё

# Гостинная
tcp.slave1.connection=192.168.1.2
tcp.slave1.type=holding
tcp.slave1.id=5
tcp.slave1.start=16384
tcp.slave1.length=16

# Спальня
tcp.slave2.connection=192.168.1.2
tcp.slave2.type=holding
tcp.slave2.id=5
tcp.slave2.start=16385
tcp.slave2.length=16
В остальном программа идентична примерам Ali.
Если есть предложения как заставить писать опенхаб по-битово выслушаю с превеликим удовольствием!

Ответить