KNX demo-stand: различия между версиями

Материал из Wiren Board
 
(не показано 20 промежуточных версий 4 участников)
Строка 1: Строка 1:
Статья в процессе наполнения. Информация может быть не полной или содержать не точности.
{{DISPLAYTITLE: Демонстрационный стенд KNX }}
 
==Описание ==
{{note|info|Информация в статье устарела}}
Выставочный демо-стенд WB-KNX. Создан, как пример использования контроллера Wiren Board с модулем KNX. Стенд оснащен оборудованием с разными шинами и протоколами, объединяя их в одну систему через контроллер WB6.  
Выставочный демо-стенд WB-KNX. Создан, как пример использования контроллера Wiren Board с модулем KNX. Стенд оснащен оборудованием с разными шинами и протоколами, объединяя их в одну систему через контроллер WB6.  
[[File:Knx_stand_2.png|250px|thumb|right|Демо-cтенд WB-KNX]]
[[File:Knx_stand_1.png|250px|thumb|right|Демо-cтенд WB-KNX]]


[[File:Knx_stand_3.png|250px|thumb|right|Диммер HDL M/D06.1, Релейный модуль  GIRA 2152 00/I01 ]]
<gallery mode="packed" heights="200px">
[[File:Knx_stand_4.png|250px|thumb|right|Панельки HDL P03.2-A и MPT14.1]]
Image: Knx_stand_2.png | Демо-cтенд WB-KNX
[[File:Knx_stand_5.png|250px|thumb|right|Контроллер WB6, релейный модуль WBIO-DO-R10A-8, модули входов WBIO-DI-DR-8 и WBIO-DI-HVD-8, датчик температуры DS18B20]]
Image: Knx_stand_1.png | Демо-cтенд WB-KNX
[[File:Knx_stand_6.png|250px|thumb|right|Modbus устройства WB-MDM2, WB-MR3LV/S, WB-MRGB]]
Image: Knx_stand_3.png | Диммер HDL M/D06.1, Релейный модуль  GIRA 2152 00/I01
[[File:Knx_stand_7.png|250px|thumb|right|Блок питания KNX Berker]]
Image: Knx_stand_4.png | Панельки HDL P03.2-A и MPT14.1
Image: Knx_stand_5.png | Контроллер WB6, релейный модуль WBIO-DO-R10A-8, модули входов WBIO-DI-DR-8 и WBIO-DI-HVD-8, датчик температуры DS18B20
Image: Knx_stand_6.png | Modbus устройства WB-MDM2, WB-MR3LV/S, WB-MRGB
Image: Knx_stand_7.png | Блок питания KNX Berker
</gallery>
== Состав ==
== Состав ==


Строка 62: Строка 65:
== Описание ==
== Описание ==


Основная идея стенда - показать взаимодействие между устройствами с разными протоколами. И то что контроллер [[Wiren Board 6]] может расширить уже существующую автоматизацию на KNX другими более дешевыми устройствами.  
Основная идея стенда - показать взаимодействие между устройствами с разными протоколами. И то, что контроллер [[Wiren Board 6]] может расширить уже существующую автоматизацию на KNX другими более дешевыми устройствами.  
Либо наоборот, если Вам захотелось добавить в проект красивую KNX панельку, при этом остальное оборудование работает по modbus. Основную информацию по сетям KNX можно найти '''[https://www.ixbt.com/home/knx-intro.shtml в этой статье]'''.  Далее подробно рассмотрим настройку стенда и написание правил.
Либо наоборот, если Вам захотелось добавить в проект красивую KNX панельку, при этом остальное оборудование работает по modbus. Далее подробно рассмотрим настройку стенда и написание правил.
[[File:Knx_stand_sch.png|450px|thumb|center|Схема Демо-Стенда WB-KNX]]
[[File:Knx_stand_sch.png|450px|thumb|center|Схема Демо-Стенда WB-KNX]]


== Настройка контроллера ==
== Настройка контроллера ==


Для начала настроим модули Wirenboard. Для этого в web-интерфейсе переходим в раздел Configs =>'''Hardware Modules Configuration''' И выбираем установленные модули. В нашем случаеː
Для начала настроим модули Wirenboard. Для этого в web-интерфейсе переходим в раздел '''Configs → Hardware Modules Configuration''' И выбираем установленные модули. В нашем случаеː


Internal slot 1 - Вставлен [[KNX Module for WB6 (WBE2-I-KNX)]], выбираем "WBE2-I-KNX: KNX/EIB TP-UART"
Internal slot 1 - Вставлен [[KNX Module for WB6 (WBE2-I-KNX)]], выбираем "WBE2-I-KNX: KNX/EIB TP-UART"
Строка 81: Строка 84:
[[File:Hwconf-knx1.PNG|250px|thumb|center|Настройка модуля WBE2-I-KNX]]  
[[File:Hwconf-knx1.PNG|250px|thumb|center|Настройка модуля WBE2-I-KNX]]  


Настраиваем modbus устройства. Для этого в web-интерфейсе переходим в раздел Configs =>'''Serial Device Driver Configuration''' и задаем нужные параметры. Как это сделать можно посмотреть в документации к устройствам, здесь подробно об этом писать не буду.
Настраиваем modbus устройства. Для этого в web-интерфейсе переходим в раздел '''Configs → Serial Device Driver Configuration''' и задаем нужные параметры. Как это сделать можно посмотреть в документации к устройствам, здесь подробно об этом писать не буду.
[[File:Mqtt-serial-knxStand.PNG|250px|thumb|center|Настройка modbus устройств]]
[[File:Mqtt-serial-knxStand.PNG|250px|thumb|center|Настройка modbus устройств]]


Следующим шагом будет установка и настройка программ для работы с KNX. А именноː '''[[Knxd]]''' - Для взаимодействия с шиной KNX, '''[[KnxTool]]''' - для отладки, '''[[WB-KNXD-CONFIG]]''' - для удобной настройки KNXD через веб-интерфейс контроллера, '''[[MQTT_KNX]]''' - для взаимодействия движка правил ('''[[Движок_правил_wb-rules]]''') c '''[[Knxd]]'''. Для установки всех программ разом введите команду в консольː
Следующим шагом будет установка и настройка программ для работы с KNX. А именноː '''[[Knxd]]''' - Для взаимодействия с шиной KNX, '''[[KnxTool]]''' - для отладки, '''[[WB-KNXD-CONFIG]]''' - для удобной настройки KNXD через веб-интерфейс контроллера, '''[[MQTT_KNX]]''' - для взаимодействия движка правил '''([[Движок правил wb-rules]])''' c '''[[Knxd]]'''. Для установки всех программ разом введите команду в консольː


<pre>$ apt-get update && apt-get install knxd knxd-tools wb-knxd-config wb-mqtt-knx</pre>
<pre>$ apt-get update && apt-get install knxd knxd-tools wb-knxd-config wb-mqtt-knx</pre>


После установки программ в web-интерфейсе переходим в раздел Configs =>'''KNXD Configuration''' для настройки KNXD.
После установки программ в web-интерфейсе переходим в раздел '''Configs → KNXD Configuration''' для настройки KNXD.


"'''Driver (-b, --layer2)'''" - В этом поле нужно указать драйвер и путь к устройству. В нашем случае указываем '''ncn5120:/dev/ttyKNX1'''
"'''Driver (-b, --layer2)'''" - В этом поле нужно указать драйвер и путь к устройству. В нашем случае указываем '''ncn5120:/dev/ttyKNX1'''
Строка 108: Строка 111:
"'''Server address'''" - Оставим именно этот адрес, что бы сервер автоматически определялся в ETS5ː '''224.0.23.12:3671'''
"'''Server address'''" - Оставим именно этот адрес, что бы сервер автоматически определялся в ETS5ː '''224.0.23.12:3671'''


Остальные настройки на данный момент нам не интересны. Сохраняем изменения нажав кнопку "Save".
Остальные настройки на данный момент нам не интересны. Сохраняем изменения нажав кнопку "Save". На этом закончим настройку контроллера и перейдем к настройке KNX устройств через ETS5.
 
== Настройка KNX устройств через ETS5 ==
 
Для настройки KNX устройств нам понадобится программа ETS5. Для наших целей сойдет бесплатная демо-версия (до 5 устройств на проект). Скачать можно с '''[https://my.knx.org/en/shop/software сайта knx.org]'''. Устанавливаем, запускаем.
 
Далее нужно выбрать интерфейс. Заходим во вкладку '''Системная Шина → Соединения → Интерфейсы'''.  Здесь во вкладке "Показать интерфейсы" отображаются автоматически найденные по бродкаст адресу интерфейсы. Если интерфейсы не определились автоматически, то во вкладке "Сконфигурированные интерфейсы" можно нажать кнопку '''"добавить" → "IP Tunneling"''' и справа ввести IP адрес контроллера с запущенным KNXD, указав порт 3671 и нажать кнопку "выбрать".
 
После этого возвращаемся в вкладку "Обзор" и создаем новый проект (или импортируем уже готовый, если имеется). В новом проекте создаем комнату и называем на пример "KNX стенд". Нажимаем на комнату '''→ Добавить → Устройство'''. Откроется вкладка каталога устройств. В нашем случае необходимых устройств в каталоге нет. Их нужно импортировать из специального файла, который распространяет производитель (HDL). Необходимые файлы можно найти '''[https://drive.google.com/drive/folders/1zZXMKCmfKpn-SUYXp7OrmiLE_DN772VW на гугл диске компании HDL]'''. Находим нужные файлы и импортируем их в ETS5, после чего добавляем нужные устройства в комнату '''KNX стенд'''.
 
Далее настраиваем каждое устройствоː задаем индивидуальный адрес, включаем необходимые функции и присваиваем им групповые адреса. Если необходимо связываем устройства групповыми адресами между собой. Полный процесс настройки описывать так же нет смысла. Для каждого устройства он индивидуальный. Ниже я оставлю ссылку на проект и все используемые для этого проекта файлы.
 
Как только все устройства настроены, адреса заданы - выбираем в верхнем меню '''→ Ввод в эксплуатацию → Загрузка → Полная загрузка →''' Следуя указаниям на экране нажимайте на кнопки "Режима загрузки" на устройствах для загрузки программ.
 
<gallery mode="packed" heights="200px">
File:Knx stand ets1.PNG|Добавляем интерфейс в ручную.
File:Knx stand ets2.PNG|Конфигурирование устройств.
File:Knx stand ets3.PNG|Загрузка программ в устройства.
</gallery>
 
После того как проект успешно загружен можно переходить к написанию правил на контроллере WB6.
 
Скачать готовый ETS5 проект стенда можно [https://wirenboard.com/wiki/images/d/d1/Wb-knx.zip по ссылке]
 
== Правила wb-rules ==
 
Зайдите в веб интерфейс контроллера и создайте новое правило во вкладке "Scripts".
 
=== Вспомогательное правило для KNX ===
 
Вспомогательное правило помогает избежать лишних действий при работе с KNX. При получении посылки в топик "knx/data" данные парсятся и раскладываются по топикам. Для каждого группового адреса создается отдельный контрол. При изменении этого контрола данные так же отправляются обратно в топик "knx/data" для отправки на шину KNX. В объекте knx_vdev_obj мы можем явно указать заранее известные групповые адреса и задать им необходимый тип.
 
<syntaxhighlight lang="ecmascript">
 
(function() {
    var knx_vdev_obj = {
        title: "KNX Group Addresses",
        cells: {
            "1-1-1": {
                type: "value",
                value: "0"
            },
            "1-1-2": {
                type: "switch",
                value: false
            },
            "1-1-3": {
                type: "range",
                max: 255,
                value: 0,
                knx_type: "wide"
            },
            "1-1-6": {
                type: "switch",
                value: false
            },
            "1-1-7": {
                type: "value",
                value: "0"
            },
            "1-1-8": {
                type: "value",
                value: "0"
            },
            "1-1-9": {
                type: "value",
                value: "0"
            },
            "1-1-10": {
                type: "switch",
                value: false
            },
            "1-1-11": {
                type: "switch",
                value: false
            },
            "1-1-12": {
                type: "value",
                value: "0"
            },
            "1-1-13": {
                type: "value",
                value: 0,
                knx_type: "wide"
            }
        }
    };
 
 
    var vdev_when_changed = [];
    var vdev_devid = "knx_group_addrs";
 
    for (var control_id in knx_vdev_obj.cells) {
        if (knx_vdev_obj.cells.hasOwnProperty(control_id)) {
            vdev_when_changed.push("knx_group_addrs/" + control_id);
        }
    }
 
    defineVirtualDevice(vdev_devid, knx_vdev_obj);
 
    defineRule("knx_vdev_feedback", {
        whenChanged: vdev_when_changed,
        then: function(newValue, devName, cellName) {
            var group_address = cellName.split("-").join("/");
            var value = +newValue;
            var write_str = "";
 
 
            if (knx_vdev_obj.cells[cellName].knx_type == "wide") {
                while (value > 0) {
                    var rem = value % 256;
                    value = Math.floor(value / 256);
                    write_str = rem + " " + write_str;
                }
                write_str = "0 " + write_str;
            } else {
                write_str = "" + value;
            }
 
            if (write_str) {
                dev["knx/data"] = "g:{} GroupValueWrite {}".format(group_address, write_str);
            }
        }
    });
 
    defineRule("knx_vdev_incoming", {
        whenChanged: "knx/data",
        then: function(newValue, devName, cellName) {
            var arr = newValue.split(/\s/);
            var sourceAddr = arr[0].split(/i\:|\,/);
            var groupAddr = arr[1].split(/g\:|\,/);
            var arr1 = newValue.split(/GroupValueWrite/);
            var value = arr1[1];
            if ((sourceAddr[1] == "0/0/0") || (sourceAddr[1] == "1/1/255")) { // skip local echo
                return;
            }
            dev[vdev_devid][groupAddr[1].split("/").join("-")] = !!parseInt(value, 16);
        }
    });
 
})()
 
 
 
function knxConvertToFloat16(value) {
    var sign = 0;
    var exp = 0;
    if (value < 0) {
        sign = 1;
    }
 
    var mant = Math.floor(value * 100);
    while ((mant < -2048) || (mant > 2047)) {
        mant = mant >> 1;
        exp += 1
    }
 
    var data = (sign << 15) | (exp << 11) | (mant & 0x07ff);
    return data;
};
</syntaxhighlight>
 
=== Основное правило ===
 
Если предыдущее правило универсальное и может быть использовано почти в каждом проекте, то это правило написано специально для нашего стенда. Здесь уже нет сложных преобразований, мы просто следим за необходимыми нам топиками и реагируем на их изменения.
 
<syntaxhighlight lang="ecmascript">
 
(function() {
 
    var channel_pairs = [
        ["knx_group_addrs/1-1-10", "wb-gpio/EXT1_R3A1"], // По нажатию на KNX кнопку, к которой привязан групповой адрес 1/1/10 включать или выключать индикатор 2
        ["knx_group_addrs/1-1-11", "wb-mr3_139/K1"]
    ];
 
 
    function makePairRules(chan1, chan2) {
        defineRule("channel_pair_follow_" + chan1 + "_" + chan2, {
            whenChanged: chan1,
            then: function(newValue, devName, cellName) {
                dev[chan2] = newValue;
            }
        });
    };
 
    for (var i = 0; i < channel_pairs.length; ++i) {
        var chan1 = channel_pairs[i][0];
        var chan2 = channel_pairs[i][1];
        makePairRules(chan1, chan2);
        makePairRules(chan2, chan1);
    }
 
 
    defineRule("hdl_panel_set_temp", {
        whenChanged: "wb-w1/28-041643cee6ff",
        then: function(newValue, devName, cellName) {
            dev["knx_group_addrs/1-1-13"] = knxConvertToFloat16(newValue + 2); // Передаем на KNX панельку температуру с датчика DS18B20
        }
    });
 
    defineRule("dimmer_chan1", {
        whenChanged: "knx_group_addrs/1-1-7",
        then: function(newValue, devName, cellName) {
            if (newValue == 11) {
                dev["wb-mdm2_1/Channel 1"] = Math.min(dev["wb-mdm2_1/Channel 1"] + 10, 100); // Если зажать KNX кнопку - увеличиваем яркость modbus диммера на 10 % единиц.
            } else if (newValue == 3) {
                dev["wb-mdm2_1/Channel 1"] = Math.max(dev["wb-mdm2_1/Channel 1"] - 10, 0);
            }
        }
    });
 
    defineRule("hdl_dimmer_chan1_on_off", {
        whenChanged: "wb-gpio/EXT2_DR1",
        then: function(newValue, devName, cellName) {
            if (newValue) {
                dev["knx_group_addrs/1-1-2"] = !dev["knx_group_addrs/1-1-2"]; // По нажатию на обычный выключатель звонкового типа переключаем KNX диммер
            }
        }
    });
 
 
    defineRule("dimmer_chan1_on_off", {
        whenChanged: "wb-gpio/EXT2_DR2",
        then: function(newValue, devName, cellName) {
            if (newValue) {
                dev["knx_group_addrs/1-1-6"] = !dev["knx_group_addrs/1-1-6"]
            }
        }
    });
    defineRule("dimmer_chan1_on_off_knx", {
        whenChanged: "knx_group_addrs/1-1-6",
        then: function(newValue, devName, cellName) {
            if (newValue) {
                dev["wb-mdm2_1/Channel 1"] = 70;
            } else {
                dev["wb-mdm2_1/Channel 1"] = 0;
            }
        }
    });
 
})();
 
function knxConvertToFloat16(value) {
    var sign = 0;
    var exp = 0;
    if (value < 0) {
        sign = 1;
    }
 
    var mant = Math.floor(value * 100);
    while ((mant < -2048) || (mant > 2047)) {
        mant = mant >> 1;
        exp += 1
    }
 
    var data = (sign << 15) | (exp << 11) | (mant & 0x07ff);
    return data;
};
</syntaxhighlight>

Текущая версия на 16:20, 12 апреля 2022

Описание

Информация в статье устарела Выставочный демо-стенд WB-KNX. Создан, как пример использования контроллера Wiren Board с модулем KNX. Стенд оснащен оборудованием с разными шинами и протоколами, объединяя их в одну систему через контроллер WB6.

Состав

Оборудование KNX

1) Панелька HDL MPT14 Controller (HDL-M/MPT14.1 v1.0-1)

2) Панелька HDL Panel 3 Rocker Controller (HDL-M/P03.2-A v.HDL-V1.2-6)

3) Диммер HDL M/D06.1

4) Релейный модуль GIRA 2152 00/I01

5) Блок питания KNX Berker

Оборудование WB

1) Wiren Board 6

2) KNX Module for WB6 (WBE2-I-KNX) (вставлен в разъем MOD1 контроллера WB6)

3) WBIO-DO-R10A-8 Relay Module

4) WBIO-DI-DR-8 I/O Module

5) Модуль наличия 220В (WBIO-DI-HVD-8)

Modbus оборудование

Порт RS485-1 (115200 8n2)

1) WB-MRGB-D (A:21)

2) WB-MD2 230V Dimmer (A:1)

3) WB-MR3LV/S(A:139)

Другое оборудование

1) Блок питания faraday 12w/12-24v/din (2шт)

2) Датчик температуры DS18B20

3) Индикаторы 220v (2шт)

4) Лампы накаливания (2шт)

5) Выключатели звонкового типа (2шт)

6) Светодиодная лента RGB

Описание

Основная идея стенда - показать взаимодействие между устройствами с разными протоколами. И то, что контроллер Wiren Board 6 может расширить уже существующую автоматизацию на KNX другими более дешевыми устройствами. Либо наоборот, если Вам захотелось добавить в проект красивую KNX панельку, при этом остальное оборудование работает по modbus. Далее подробно рассмотрим настройку стенда и написание правил.

Схема Демо-Стенда WB-KNX

Настройка контроллера

Для начала настроим модули Wirenboard. Для этого в web-интерфейсе переходим в раздел Configs → Hardware Modules Configuration И выбираем установленные модули. В нашем случаеː

Internal slot 1 - Вставлен KNX Module for WB6 (WBE2-I-KNX), выбираем "WBE2-I-KNX: KNX/EIB TP-UART"

External I/O module 1 - подключен модуль WBIO-DO-R10A-8 Relay Module, выбираем "WBIO-DO-RxA-8: 8 Channel Relay I/O module"

External I/O module 2 - подключен модуль WBIO-DI-DR-8 I/O Module, выбираем "WBIO-DI-DR-8: Digital inputs (dry contact) I/O module"

External I/O module 3 - подключен Модуль наличия 220В (WBIO-DI-HVD-8), выбираем "WBIO-DI-HVD-8: High Voltage Digital Inputs I/O module"

После этого нажимаем кнопку "Save".

Настройка модуля WBE2-I-KNX

Настраиваем modbus устройства. Для этого в web-интерфейсе переходим в раздел Configs → Serial Device Driver Configuration и задаем нужные параметры. Как это сделать можно посмотреть в документации к устройствам, здесь подробно об этом писать не буду.

Настройка modbus устройств

Следующим шагом будет установка и настройка программ для работы с KNX. А именноː Knxd - Для взаимодействия с шиной KNX, KnxTool - для отладки, WB-KNXD-CONFIG - для удобной настройки KNXD через веб-интерфейс контроллера, MQTT_KNX - для взаимодействия движка правил (Движок правил wb-rules) c Knxd. Для установки всех программ разом введите команду в консольː

$ apt-get update && apt-get install knxd knxd-tools wb-knxd-config wb-mqtt-knx

После установки программ в web-интерфейсе переходим в раздел Configs → KNXD Configuration для настройки KNXD.

"Driver (-b, --layer2)" - В этом поле нужно указать драйвер и путь к устройству. В нашем случае указываем ncn5120:/dev/ttyKNX1

"EIB address (-e, --eibaddr)" - задаем EIB адрес нашему контроллеру 1.1.255

"Client-addrs (-E, --client-addrs)" - указываем диапазон адресов, которые будут выдаваться EIB клиентам 1.1.5:50

"Discovery (-D, --Discovery)" - Ставим галку, что бы контроллер отвечал на запросы поиска.

"Tunnelling (-T, --Tunnelling)" - Ставим галку

"Routing (-R, --Routing)" - Ставим галку

"Server (-S, --Server)" - Тоже ставим галку, что бы включить EIBnet/IP multicast сервер на контроллере

"Custom name of the server" - Произвольное имя сервера. Впишем WirenboardKNX

"Server address" - Оставим именно этот адрес, что бы сервер автоматически определялся в ETS5ː 224.0.23.12:3671

Остальные настройки на данный момент нам не интересны. Сохраняем изменения нажав кнопку "Save". На этом закончим настройку контроллера и перейдем к настройке KNX устройств через ETS5.

Настройка KNX устройств через ETS5

Для настройки KNX устройств нам понадобится программа ETS5. Для наших целей сойдет бесплатная демо-версия (до 5 устройств на проект). Скачать можно с сайта knx.org. Устанавливаем, запускаем.

Далее нужно выбрать интерфейс. Заходим во вкладку Системная Шина → Соединения → Интерфейсы. Здесь во вкладке "Показать интерфейсы" отображаются автоматически найденные по бродкаст адресу интерфейсы. Если интерфейсы не определились автоматически, то во вкладке "Сконфигурированные интерфейсы" можно нажать кнопку "добавить" → "IP Tunneling" и справа ввести IP адрес контроллера с запущенным KNXD, указав порт 3671 и нажать кнопку "выбрать".

После этого возвращаемся в вкладку "Обзор" и создаем новый проект (или импортируем уже готовый, если имеется). В новом проекте создаем комнату и называем на пример "KNX стенд". Нажимаем на комнату → Добавить → Устройство. Откроется вкладка каталога устройств. В нашем случае необходимых устройств в каталоге нет. Их нужно импортировать из специального файла, который распространяет производитель (HDL). Необходимые файлы можно найти на гугл диске компании HDL. Находим нужные файлы и импортируем их в ETS5, после чего добавляем нужные устройства в комнату KNX стенд.

Далее настраиваем каждое устройствоː задаем индивидуальный адрес, включаем необходимые функции и присваиваем им групповые адреса. Если необходимо связываем устройства групповыми адресами между собой. Полный процесс настройки описывать так же нет смысла. Для каждого устройства он индивидуальный. Ниже я оставлю ссылку на проект и все используемые для этого проекта файлы.

Как только все устройства настроены, адреса заданы - выбираем в верхнем меню → Ввод в эксплуатацию → Загрузка → Полная загрузка → Следуя указаниям на экране нажимайте на кнопки "Режима загрузки" на устройствах для загрузки программ.

После того как проект успешно загружен можно переходить к написанию правил на контроллере WB6.

Скачать готовый ETS5 проект стенда можно по ссылке

Правила wb-rules

Зайдите в веб интерфейс контроллера и создайте новое правило во вкладке "Scripts".

Вспомогательное правило для KNX

Вспомогательное правило помогает избежать лишних действий при работе с KNX. При получении посылки в топик "knx/data" данные парсятся и раскладываются по топикам. Для каждого группового адреса создается отдельный контрол. При изменении этого контрола данные так же отправляются обратно в топик "knx/data" для отправки на шину KNX. В объекте knx_vdev_obj мы можем явно указать заранее известные групповые адреса и задать им необходимый тип.

(function() {
    var knx_vdev_obj = {
        title: "KNX Group Addresses",
        cells: {
            "1-1-1": {
                type: "value",
                value: "0"
            },
            "1-1-2": {
                type: "switch",
                value: false
            },
            "1-1-3": {
                type: "range",
                max: 255,
                value: 0,
                knx_type: "wide"
            },
            "1-1-6": {
                type: "switch",
                value: false
            },
            "1-1-7": {
                type: "value",
                value: "0"
            },
            "1-1-8": {
                type: "value",
                value: "0"
            },
            "1-1-9": {
                type: "value",
                value: "0"
            },
            "1-1-10": {
                type: "switch",
                value: false
            },
            "1-1-11": {
                type: "switch",
                value: false
            },
            "1-1-12": {
                type: "value",
                value: "0"
            },
            "1-1-13": {
                type: "value",
                value: 0,
                knx_type: "wide"
            }
        }
    };


    var vdev_when_changed = [];
    var vdev_devid = "knx_group_addrs";

    for (var control_id in knx_vdev_obj.cells) {
        if (knx_vdev_obj.cells.hasOwnProperty(control_id)) {
            vdev_when_changed.push("knx_group_addrs/" + control_id);
        }
    }

    defineVirtualDevice(vdev_devid, knx_vdev_obj);

    defineRule("knx_vdev_feedback", {
        whenChanged: vdev_when_changed,
        then: function(newValue, devName, cellName) {
            var group_address = cellName.split("-").join("/");
            var value = +newValue;
            var write_str = "";


            if (knx_vdev_obj.cells[cellName].knx_type == "wide") {
                while (value > 0) {
                    var rem = value % 256;
                    value = Math.floor(value / 256);
                    write_str = rem + " " + write_str;
                }
                write_str = "0 " + write_str;
            } else {
                write_str = "" + value;
            }

            if (write_str) {
                dev["knx/data"] = "g:{} GroupValueWrite {}".format(group_address, write_str);
            }
        }
    });

    defineRule("knx_vdev_incoming", {
        whenChanged: "knx/data",
        then: function(newValue, devName, cellName) {
            var arr = newValue.split(/\s/);
            var sourceAddr = arr[0].split(/i\:|\,/);
            var groupAddr = arr[1].split(/g\:|\,/);
            var arr1 = newValue.split(/GroupValueWrite/);
            var value = arr1[1];
            if ((sourceAddr[1] == "0/0/0") || (sourceAddr[1] == "1/1/255")) { // skip local echo
                return;
            }
            dev[vdev_devid][groupAddr[1].split("/").join("-")] = !!parseInt(value, 16);
        }
    });

})()



function knxConvertToFloat16(value) {
    var sign = 0;
    var exp = 0;
    if (value < 0) {
        sign = 1;
    }

    var mant = Math.floor(value * 100);
    while ((mant < -2048) || (mant > 2047)) {
        mant = mant >> 1;
        exp += 1
    }

    var data = (sign << 15) | (exp << 11) | (mant & 0x07ff);
    return data;
};

Основное правило

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

(function() {

    var channel_pairs = [
        ["knx_group_addrs/1-1-10", "wb-gpio/EXT1_R3A1"], // По нажатию на KNX кнопку, к которой привязан групповой адрес 1/1/10 включать или выключать индикатор 2
        ["knx_group_addrs/1-1-11", "wb-mr3_139/K1"]
    ];


    function makePairRules(chan1, chan2) {
        defineRule("channel_pair_follow_" + chan1 + "_" + chan2, {
            whenChanged: chan1,
            then: function(newValue, devName, cellName) {
                dev[chan2] = newValue;
            }
        });
    };

    for (var i = 0; i < channel_pairs.length; ++i) {
        var chan1 = channel_pairs[i][0];
        var chan2 = channel_pairs[i][1];
        makePairRules(chan1, chan2);
        makePairRules(chan2, chan1);
    }


    defineRule("hdl_panel_set_temp", {
        whenChanged: "wb-w1/28-041643cee6ff",
        then: function(newValue, devName, cellName) {
            dev["knx_group_addrs/1-1-13"] = knxConvertToFloat16(newValue + 2); // Передаем на KNX панельку температуру с датчика DS18B20
        }
    });

    defineRule("dimmer_chan1", {
        whenChanged: "knx_group_addrs/1-1-7",
        then: function(newValue, devName, cellName) {
            if (newValue == 11) {
                dev["wb-mdm2_1/Channel 1"] = Math.min(dev["wb-mdm2_1/Channel 1"] + 10, 100); // Если зажать KNX кнопку - увеличиваем яркость modbus диммера на 10 % единиц.
            } else if (newValue == 3) {
                dev["wb-mdm2_1/Channel 1"] = Math.max(dev["wb-mdm2_1/Channel 1"] - 10, 0);
            }
        }
    });

    defineRule("hdl_dimmer_chan1_on_off", {
        whenChanged: "wb-gpio/EXT2_DR1",
        then: function(newValue, devName, cellName) {
            if (newValue) {
                dev["knx_group_addrs/1-1-2"] = !dev["knx_group_addrs/1-1-2"]; // По нажатию на обычный выключатель звонкового типа переключаем KNX диммер
            }
        }
    });


    defineRule("dimmer_chan1_on_off", {
        whenChanged: "wb-gpio/EXT2_DR2",
        then: function(newValue, devName, cellName) {
            if (newValue) {
                dev["knx_group_addrs/1-1-6"] = !dev["knx_group_addrs/1-1-6"]
            }
        }
    });
    defineRule("dimmer_chan1_on_off_knx", {
        whenChanged: "knx_group_addrs/1-1-6",
        then: function(newValue, devName, cellName) {
            if (newValue) {
                dev["wb-mdm2_1/Channel 1"] = 70;
            } else {
                dev["wb-mdm2_1/Channel 1"] = 0;
            }
        }
    });

})();

function knxConvertToFloat16(value) {
    var sign = 0;
    var exp = 0;
    if (value < 0) {
        sign = 1;
    }

    var mant = Math.floor(value * 100);
    while ((mant < -2048) || (mant > 2047)) {
        mant = mant >> 1;
        exp += 1
    }

    var data = (sign << 15) | (exp << 11) | (mant & 0x07ff);
    return data;
};