Если вы не знакомы с системами автоматизации и стандартом KNX, то нужную информацию можете получить в гугле или с официальных сайтов. Если же вы работаете с данным стандартом — то многие вещи вам будут понятны, и, возможно, вас, как и меня, давно интересует вопрос каким же образом можно получить доступ к физической шине KNX, минуя IP роутеры.
Далее я покажу каким образом я решил для себя эту задачу, используя Raspberry Pi и модуль KNX BAOS 838 kBerry от Weinzierl.
Мотивация
Стандарт KNX подразумевает собой децентрализованную систему, работоспособную в отсутствии центрального контроллера ПЛК. Децентрализация обеспечивает надежность, но отсутствие ПЛК в системе лишает нас необходимой нам гибкости. Можно использовать различные IP шлюзы, и общаться по UPD с сервера, но это решение не рассматривал, поскольку доступ напрямую к шине выглядит надежнее.
Существующие решения
На рынке можно найти решения для данной задачи, со следующими из них я плотно работал:
Loxone Miniserver
- Цена: ~600 евро
- Плюс: своя шина, большой ассортимент устройств.
- Плюс: простой конфигуратор, программирование логики блоками, хорошая документация.
- Минус: нету возможности программировать на языках высокого уровня. Есть встроенный интерпретатор PicoC, но на нем проблематично реализовать, для примера, доступ к облаку.
iRidium Server для UMC
- Цена: рекомендуемая розничная 119000р, или ~1700 евро.
- Плюс: поддержка большого количества систем автоматизации, помимо KNX.
- Плюс: поддержка JavaScript.
- Минус: файл проекта — zip архив, что усложняет его редактирование. Т.е. для того чтобы отредактировать скрипт, вам надо либо использовать iRidium Studio с встроенным редактором скриптов, в котором нету прелестей привычного вам IDE/редактора, либо придумать способ распаковки/сборки проекта.
- Минус: JavaScript движок. Для примера, нету привычного setTimeout/setInterval, вместо них IR.SetTimeout/IR.SetInterval. Нету совместимости с nodejs.
- Минус: стабильность работы, частые перезагрузки.
EVIKA LogicMachine
- Цена: ~3000 евро.
- Плюс: помимо KNX TP/UART на плате имеются интерфейсы RS-485, RS-232 и прочие, в зависимости от конфигурации.
- Плюс: язык lua, cron расписания, и прочее.
Некоторые решения хороши, но отталкивает цена, плюс хотелось бы использовать больше гибкости в программировании.
Решение
Задача решилась с использованием Raspberry Pi и модуль Weinzierl KNX BAOS Module 838 kBerry.
Стоимость модуля ~70 евро, в сумме с Raspberry Pi + блок питания, корпус на DIN рейку выходит около 150 евро.
В качестве среды выполнения используется nodejs, из зависимостей модуль "serialport" для общения с UART.
Наше приложение подключается по серийному порту к модулю BAOS 838 и общается посредством ObjectServer protocol, описание которого можно найти по ссылке в конце статьи.
Фрейм с данными заключается в протокол FT1.2 следующим образом:
|0x68|L|L|0x68|CR|data|C|0x16|
где L - длина данных data +1 для контрольного байта
CR - контрольный байт, равен 0x73 для нечетных, 0x53 для четных фреймов,
C - чексумма = (сумма байт данных + контрольного байта) mod 256
Также есть фреймы с постоянной длиной, такие как reset request, reset indication, acknowledge frame.
Reset request отправляется при открытие соединения, reset indication отправляется с модуля baos 838 к Raspberry Pi при сбросе модуля, acknowledge отправляет каждая сторона при приеме данных.
Данные data состоят из следующих полей:
| Поле | Размер | Описание
| MainService | 1 | Главный сервис. Везде 0xF0
| SubService | 1 | Сервис. Их три вида: запросы, ответы, индикация.
| StartItem | 2 | ID первого элемента
| NumberOfItems | 2 | Максимальное количество элементов
...
И далее в зависимости от сервиса. Эти четыре поля присутствуют во всех сообщениях.
Схема коммуникации:
- Наше приложение (клиент) отправляет reset request.
- BAOS 838 (сервер) отправляет acknowledge.
- Клиент отправляет первый запрос(для примера GetDatapointDescription.Req). Нечетный фрейм.
- Сервер получает запрос, отправляет acknowledge.
- Сервер отправляет ответ на запрос.
- Клиент отправляет подтверждение acknowledge.
....
Подключение
Модуль подключается к GPIO контактам платы Raspberry Pi, более подробно можно узнать по ссылкам в конце статьи.
ETS
Как и любое KNX устройство, BAOS 838 module конфигурируется через ETS. Аппликация в данном случае используется "KNX BAOS 830", ее можно скачать с официального сайта производителя. Устройство поддерживает до 1000 групповых адресов.
Настройка Raspberry Pi
Первым делом устанавливаем raspbian-stretch-lite, настраиваем доступ по ssh.
Далее, настраиваем UART интерфейс. Для Raspberry Pi 3:
sudo sh -c "echo dtoverlay=pi3-miniuart-bt >>/boot/config.txt"
Из /boot/cmdline.txt убираем запись console=serial0,115200
Добавляем пользователя в группу dialout:
sudo usermod -a -G dialout YOURUSERNAME
Перезагружаемся
reboot
Устанавливаем nodejs, git:
curl -sL https://deb.nodesource.com/setup_8.x | sudo -E bash -
sudo apt-get install -y nodejs git
Подготовка закончена, переходим к нашему проекту.
bobaos-cli
Для тестирования можно использовать простой интерфейс для командной строки. Устанавливаем:
sudo npm install -g bobaos-cli
Запускаем:
% bobaos-cli
bobaos> help
Commands:
help [command...] Provides help for a given command.
exit Exits application.
open [options] Open serial port
getDatapointDescription [options] GetDatapointDescription.Req service
setDatapointValue [options] SetDatapointValue.Req service with command "set and send to bus"
readDatapointFromBus [options] SetDatapointValue.Req service with command "read via bus"
getDatapointValue [options] GetDatapointValue.Req service
getParameterByte [options] GetParameterByte.Req service
Далее мы открываем порт командой open. По умолчанию открывается соединение с устройством /dev/ttyAMA0, если в системе другой интерфейс, используем опцию -p, --port.
Далее, мы можем получить информацию о сконфигурированных датапоинтах:
bobaos> getDatapointDescription -s 1 -n 10
{ service: 'GetDatapointDescription.Res',
direction: 'response',
error: false,
start: 1,
number: 10,
payload:
[ { id: 1, valueType: 8, configFlags: 95, dpt: 'dpt9' },
{ id: 2, valueType: 7, configFlags: 87, dpt: 'dpt5' },
{ id: 3, valueType: 7, configFlags: 87, dpt: 'dpt5' },
{ id: 4, valueType: 7, configFlags: 87, dpt: 'dpt5' },
{ id: 5, valueType: 7, configFlags: 87, dpt: 'dpt5' },
{ id: 6, valueType: 0, configFlags: 95, dpt: 'dpt1' },
{ id: 7, valueType: 0, configFlags: 95, dpt: 'dpt1' },
{ id: 8, valueType: 0, configFlags: 87, dpt: 'dpt1' },
{ id: 9, valueType: 0, configFlags: 87, dpt: 'dpt1' },
{ id: 10, valueType: 14, configFlags: 87, dpt: 'dpt16' } ] }
bobaos>
В моем случае первый — датчик температуры, далее идет несколько однобайтных значения, несколько однобитных, и строковое значение dpt16.
Получаем значения:
bobaos> getDatapointValue -s 1 -n 10
{ service: 'GetDatapointValue.Res',
direction: 'response',
error: false,
start: 1,
number: 10,
payload:
[ { id: 1, state: 16, length: 2, value: <Buffer 0c bf> },
{ id: 2, state: 0, length: 1, value: <Buffer 00> },
{ id: 3, state: 0, length: 1, value: <Buffer 00> },
{ id: 4, state: 0, length: 1, value: <Buffer 00> },
{ id: 5, state: 0, length: 1, value: <Buffer 00> },
{ id: 6, state: 0, length: 1, value: <Buffer 00> },
{ id: 7, state: 0, length: 1, value: <Buffer 00> },
{ id: 8, state: 0, length: 1, value: <Buffer 00> },
{ id: 9, state: 0, length: 1, value: <Buffer 00> },
{ id: 10,
state: 0,
length: 14,
value: <Buffer 00 00 00 00 00 00 00 00 00 00 00 00 00 00> } ] }
bobaos>
Значения возвращаются в непреобразованном виде, для преобразования можно использовать библиотеку knx-dpts-baos, поддерживающую типы от dpt1 до dpt18.
Устанавливаем значение:
bobaos> setDatapointValue -s 2 -v 128 -t dpt5
{ service: 'SetDatapointValue.Res',
direction: 'response',
error: false,
start: 2,
number: 0,
payload: null }
bobaos> getDatapointValue -s 2
{ service: 'GetDatapointValue.Res',
direction: 'response',
error: false,
start: 2,
number: 1,
payload: [ { id: 2, state: 16, length: 1, value: <Buffer 80> } ] }
bobaos>
bobaos-cli можно использовать для быстрого тестирования, установки, чтения данных с шины.
Использование в приложениях
Устанавливаем npm пакет:
npm install --save bobaos
Добавляем в наш скрипт:
const Baos = require('bobaos');
const app = new Baos({serialPort: {device: '/dev/ttyAMA0'}, debug: false});
// send requests after successful initial reset
app.on('open', () => {
app
.getDatapointDescription(1, 10)
.getParameterByte(1, 10)
.readDatapointFromBus(1, 2) // good
.readDatapointFromBus(1, 10) // error!
.getDatapointValue(1, 10)
.setDatapointValue(2, Buffer.alloc(1, 0xc0))
.getDatapointValue(2);
});
// listen to incoming events and responses
app.on('service', console.log);
Вывод должен выглядить примерно так:
{ service: 'GetParameterByte.Res',
error: false,
start: 1,
number: 10,
payload: <Buffer 01 03 05 07 09 0b 0a 00 00 00> }
{ service: 'SetDatapointValue.Res',
error: false,
start: 1,
number: 0,
payload: null }
{ service: 'GetDatapointValue.Res',
error: false,
start: 1,
number: 1,
payload: [ { id: 1, state: 4, length: 2, value: <Buffer 0c fb> } ] }
....
....
Теперь мы вправе экспериментировать как нам угодно, создавать любые скрипты, использовать возможности nodejs, npm пакетов. Впереди еще много работы, но начало положено хорошее, что радует и мотивирует продолжать дальше.
Ссылки
- Репозиторий на github
- KNX BAOS Module 838 kBerry. По ссылке можно посмотреть информацию, скачать аппликацию для ETS.
- Описание протокола
- Официальная документация по установке на Raspberry Pi
Комментарии (6)
evgeny_boger
16.01.2018 00:23Существующие решения
Ещё есть Wiren Board с KNX-модулем, одна штука выходит около 25 000р в сумме.
И даже ETS не нужен, нужно только телеграммы туда-сюда слать из JS-движка правил.bobalus Автор
16.01.2018 00:44А вот npm модуль прикрутить к JS-движку каким образом? Для примера — если задача сделать mqtt шлюз для KNX, или плагин для homebridge.
В моем списке нету, т.к. не работал с вашим оборудованием. Но, когда искал информацию как оформить статью, наткнулся на вашу статью, оттуда же взял и раздел «Мотивация» :)
Заинтересовался, почитал вас. Живу недалеко от Долгопрудного, если что могу заехать к вам. Но это если есть время, желание.evgeny_boger
16.01.2018 02:21npm-модуль без изменений к нашему движку не прикрутить к сожалению, потому что у нас там тоже не нода и не V8, а свой сервис на интерпретаторе duktape.
С другой стороны,
1) Можно запустить «чистую» ноду на WB, как и на любом контроллере с Linux
2) mqtt-шлюз для KNX — это у нас функциональность из коробки, для этого есть специальный наш сервис, wb-mqtt-knx (исходники на гитхабе)
Заходите в гости как будет время, всё расскажем и покажем
lingvo
Вопрос — можно ли это все подключить к Nodered, чтобы сделать вот так: https://geektimes.ru/post/279814/
Например приделав протокол MQTT?
bobalus Автор
Да, можно. Причем вариантов несколько.
Первый, полагаю более сложный в разработке, в случае если node-red крутится на Raspberry Pi, можно написать плагин для node-red, который напрямую взаимодействует с шиной KNX, получает с node-red значения, отправляет их.
Второй, как предлагаете, реализовать MQTT.
Реализация в данном случае будет выглядеть примерно так:
lingvo
Было бы неплохо заиметь MQTT, тогда — этакий шлюз MQTT — KNX. На форумах по домашней автоматизации — желанная штука