Команды устройствам и ответы

Нажатие на панели — это только намерение. Чтобы что-то произошло в зале, программа должна отправить устройству команду. Чтобы на панели было видно, что произошло на самом деле, она должна принять ответ. На этой странице два узла (блока программы U-Logic): device - command отправляет команду, device - response - listener принимает ответ.

Эти же два узла вы уже использовали в «Первой программе»: блоки B–D там — самый короткий путь «нажали — команда — ответ — подпись». Блоки H и I (страница «Устройства») показывают ответы звукового процессора и кодека и то, что с ними делать. Здесь узлы разобраны подробнее.

Что нужно заранее: событие с панели уже принято и разложено по выходам ui - switch («Приём событий»), а драйвер устройства (описание протокола: команды, их параметры и разбор ответов) и подключение к нему созданы (как — в разделе «По шагам: подключить устройство и отправить команду»). Здесь — только то, что нужно для связи с интерфейсом; окна узлов подробно разобраны на странице «Узлы Dynamic Driver».

device - command: команда устройству

Зачем. Отправить устройству команду из его драйвера: «подать вход 2 на выход 1», «позвонить», «выключить микрофон».

Поля окна и выходы узла описаны в разделе device - command. Главное для связи с интерфейсом: «Соединение» и «Команда» обязательны (без соединения узел показывает «Не настроено соединение»), а «Параметры команды» задают значения по умолчанию.

../../_images/device-command-edit.png

Окно узла device - command «Кодек: команда»: 1 — «Соединение», 2 — «Команда», 3 — «Параметры команды»

В «Демо-зале» команда и параметры приходят в сообщении: msg.command (вместо команды из окна) и msg.parameters (сливается с параметрами из окна, сообщение главнее). Первый выход узла — состояние соединения, второй — копия входного сообщения без msg.command и msg.parameters; ответ устройства из device - command не выходит: его принимает device - response - listener. Пока устройство не подключено, команда теряется.

Как команда получает параметры из события

device - command не знает про интерфейс: ему важно только сообщение. Имя кнопки и значение из события превращает в команду и параметры узел перед ним. В «Демо-зале» так:

  • Один device - command на устройство. Команду в узел кладёт предыдущий узел в msg.command, параметры — в msg.parameters. Например, для кодека: «Контакты» → getContacts, «История» → getHistory, «Позвонить» → dial с номером в параметрах, «Завершить» → hangup, микрофон → setMute. Все команды идут в один узел «Кодек: команда».

  • Элемент не привязывается к команде в окне. Привязка — это путь по проводам: правило ui - switch → узел, который готовит команду → device - command.

  • Команда без соединения теряется. Поэтому подписки и запросы статуса запускают от первого выхода узла. Когда он сообщил «connected», в блоке «Шаги сценариев и подписки» через паузу отправляются подписки звукового процессора. Зачем нужна подписка и почему после подключения пауза — в «Первой программе», блок H.

Подготовить команду проще всего узлом change. Есть два случая.

Фиксированная команда: change с константами

Команда и параметры всегда одни и те же, поэтому достаточно двух правил «Установить»: msg.command — «строка» с именем команды, msg.parameters — «JSON» с параметрами (или одно правило, если параметров нет). В «Демо-зале» так сделаны «Завершить» (msg.command = hangup) и «Список: контакты» (getContacts), а микрофон — setMute с {"mute": false} или {"mute": true}. Названия команд и полей параметров берите в окне device - command: список «Команда» и блок «Параметры команды».

Команда зависит от кнопки: карта кнопок

Кнопок много, и у каждой свои параметры (каждый источник — свой вход матрицы). Вместо узла change на каждую кнопку заведите таблицу «кнопка → параметры» в памяти программы и один change, который достаёт из неё строку по имени нажатой кнопки: msg.parameters = flow. (или global.) demoMatrix[msg.payload.object], с флажком «Deep copy value» («глубокая копия»). Так сделан блок «Экран» в «Демо-зале»: одно правило Src_*_b, один change «Кнопка → параметры матрицы» и один device - command «Матрица: подать вход». Таблица записывается один раз при запуске (блок «Старт»). Как это устроено и почему работает, подробно описано в «Первой программе», блоки A и C. Там же есть более наглядный вариант, где на каждую кнопку свой change.

Для тех, кто программирует: function

Если подготовка команды сложнее «взять по ключу» (проверка условий, выбор из нескольких источников, сообщение пользователю), можно написать её узлом function (свой код). В «Демо-зале» так сделана кнопка «Позвонить»: функция «Позвонить выбранному» берёт из памяти строку, выбранную в списке, и, если ничего не выбрано, предупреждает об этом вместо команды. Дайте узлу понятное имя и напишите в комментарии в начале, что он принимает и что выдаёт («вход / выход»). Для новичка function не нужен: всё из этой страницы делается узлами change и switch.

Сценарий из нескольких команд

Кнопка «Начало совещания» на главной включает микрофоны, звук и матрицу сразу. В «Демо-зале» такой сценарий — список шагов [{устройство, команда, параметры}], который лежит в узле change. Узлы «Шаги: …» передают список в блок «Шаги сценариев и подписки». Там split разбирает список, delay (0,4 с) делает паузу между шагами, change превращает шаг в msg.command и msg.parameters, switch выбирает нужное устройство, и шаг уходит в device - command этого устройства. Поэтому «Выключить все» места — это один change со списком из 13 шагов, а не 13 проводов. Окно подтверждения «Выключить всё» делается в интерфейсе (фрейм с кнопкой «Выключить»): программа получает только нажатие «Выключить».

device - response - listener: ответ устройства

Зачем. Вернуть на панель то, что произошло на самом деле. Нажатие — это намерение, ответ устройства — факт: источник могли переключить с пульта или сценарием, команда могла не пройти. Кнопка, подсвеченная по ответу, не «врёт».

Как настроить окно — в разделе device - response - listener: то же «Соединение», что у device - command, число выходов и таблица «Типы ответов» с номером выхода для каждого типа. Ответ, для которого выход не выбран, уходит на первый выход.

../../_images/listener-edit.png

Окно узла device - response - listener «Кодек: ответы»: 1 — «Соединение», 2 — «Выходы», 3 — «Типы ответов» и номера выходов

Что приходит: msg.payload содержит ответ драйвера, тип ответа — в msg.payload.type; к какому устройству относится ответ — в msg.device.

Как выглядят ответы

Состав полей зависит от драйвера. Проще всего увидеть его в отладке: подключите к выходу device - response - listener узел debug («весь msg») и вызовите ответ. Ответы устройств «Первой программы», как они приходят в msg.payload:

Устройство и тип ответа

Что в msg.payload

Что из него берут

Звуковой процессор, subscribeNotification

{"publishToken": "fpHallMute", "value": true, "valueType": "bool", "type": "subscribeNotification"} — для уровня value число в дБ, например -20

имя подписки publishToken — какая это величина; value — её значение

Кодек, callInfo

{"inCall": false, "info": null, "value": false, "type": "callInfo"} — при разговоре inCall: true, в info абонент и время

inCall — идёт ли разговор

Кодек, contacts

{"list": [{"id": 1, "name": "Переговорная 2", "number": "1002", "status": null, "type": "SIP"}, …], "value": 4, "type": "contacts"}

массив list: у каждого контакта name и number

Матрица, route

{"type": "route", "input": 2, "output": 1, "ack": true, "value": 2, "key": "1"}

input, output, ack — подтверждено ли

Как получить из такого ответа значение для панели, разобрано по примерам на странице «Изменение вида на панели». Для этого в узле change пишут выражение над msg.payload, а результат кладут в msg.topic для api - helper - 2. Примеры: кнопка по value (пример 1), ползунок и надпись по уровню в дБ (пример 2), текст и цвет по inCall (пример 3), список по list (пример 4).

Что слушает «Демо-зал»:

Устройство

Что приходит

Что делает поток

Матрица

ответ на route

после фильтров «Подтверждено?» и «Какой выход?» подсвечивает источник, пишет «На экране: …»

Звуковой процессор

уведомления подписок

двигает ползунки, нажимает и отпускает кнопки mute, считает «Говорят»

Кодек ВКС

contacts, history, callInfo

заполняет список, меняет «Идёт разговор» / «Нет звонка» и цвет плашки

Фильтр ответа: switch

Один драйвер присылает ответы на разные команды и по разным выходам устройства. Матрица, например, отвечает «выход 2 ← вход 1», даже если вы работаете с экраном зала на выходе 1. Чтобы ответ не попал не в ту подпись, поставьте после device - response - listener обычный узел switch:

  1. Свойство — поле ответа, по которому выбираете (msg.payload.output).

  2. По одному правилу «==» на каждое значение: выход 1 — одна ветка (экран зала), выход 2 — другая (экран председателя). Ответ по выходу, которого нет среди правил, дальше не идёт.

  3. Если драйвер сообщает об операции дважды (при отправке и по ответу устройства), первым поставьте switch по признаку подтверждения (msg.payload.ack «равно true»).

Так сделано в «Первой программе» (блок D, switch «Подтверждено?» и «Какой выход?») и в блоке «Экран» «Демо-зала».

Ответ → вид элементов

Дальше ответ превращают в сообщение для api - helper - 2 (как — на странице «Изменение вида на панели», с готовыми примерами для звука и ВКС) или interlock - 2 («Переключатели и группы») и отправляют в UI - Panel out.

Имя подписки = имя элемента. Звуковой процессор присылает уведомление вместе с именем, под которым оформлена подписка. Если подписку назвать именем кнопки (Mic_04_b, Snd_Hall_vol_sl, Hdr_Sound_b), уведомление само указывает, какой элемент менять. В блоке «Звуковой процессор: ответы → вид элементов» узел switch «Чьё уведомление» (проверка всех правил) отправляет уведомления мест Mic_* в два места: в блок «Микрофоны» и в шаблон «Кнопки по имени». Остальные кнопки он отправляет в шаблон вида { "{{payload.publishToken}}": { "uiState": "default" или "pressed" } } (поле с именем подписки в ответе этого драйвера называется publishToken) и дальше в api - helper - 2 «Кнопки по имени». Один шаблон работает для всех кнопок с mute: добавили новую подписку — менять поток не нужно.

../../_images/block-sound-feedback.png

Блок 9 «Звуковой процессор: ответы → вид элементов»: 1 — «Звук: уведомления», 2 — «Чьё уведомление», 3 — шаблоны по имени кнопки «Кнопка: обычная» и «Кнопка: нажата», 4 — api - helper - 2 «Кнопки по имени», 5 — ветки ползунков и подписей «Зал» и «ВКС»

Опрос, если устройство само не сообщает. Кодек не присылает состояние звонка сам, поэтому узел inject каждые 5 секунд посылает ему getCallInfo, а ответ callInfo с признаком inCall меняет надписи.

Частые ошибки

  • Ответ команды ищут на выходе device - command. Ответ устройства приходит только в device - response - listener. Выход 2 — сквозная копия сообщения, она уходит сразу.

  • Команда не доходит. У device - command не выбрано «Соединение» (в состоянии узла «Не настроено соединение») или устройство ещё не подключилось. Подключение смотрите по статусу узла и по первому выходу.

  • Подписки и запросы статуса не срабатывают. Они ушли до подключения. Запускайте их от первого выхода device - command.

  • Подсвечивается не та кнопка или совсем не подсвечивается. Подсветка идёт по ответу устройства: проверьте, дошёл ли ответ до device - response - listener, тот ли выбран тип ответа и тот ли выход. Если ответ приходит, но имя в interlock - 2 не подходит, исправьте имя, которое вы кладёте на его вход.

  • Устройство ответило, но ничего не поменялось на панели. Ответ дошёл до device - response - listener, но не подключён ни к api - helper - 2, ни к interlock - 2, либо их выход не подключён к UI - Panel out.