Демонстрационный стенд KNX

Материал из Wiren Board
Это утверждённая версия страницы. Она же — наиболее свежая версия.

Описание

Информация в статье устарела Выставочный демо-стенд 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;
};