Первая программа по шагам
Эта страница — начало раздела. На маленьком учебном примере вы пройдёте весь путь, из которого состоит любая программа для панели: нажали кнопку → программа отправила команду устройству → устройство ответило → на панели поменялись подпись и подсветка. Когда понятна одна цепочка, остальные страницы раздела и большая программа «Демо-зал» отличаются только числом кнопок и устройств.
Программа «Первая программа» учит девяти приёмам. Каждому посвящён свой блок на вкладке (рабочем листе программы). Блоки названы буквами A–I; буквы есть только в этой инструкции, на вкладке блоки подписаны словами:
Блок |
Что показывает |
|---|---|
A. Старт: карты |
как записать в память программы «таблицу соответствий» при запуске |
B. Наглядно: правило на кнопку |
самый простой способ: на каждую кнопку — своё правило и свои параметры |
C. Компактно: карта входов |
то же самое для любого числа кнопок: одно правило и таблица |
D. Ответ матрицы: надписи и подсветка |
как вернуть на панель то, что произошло на самом деле, и отфильтровать лишние ответы |
E. Микрофон через switch |
кнопка-переключатель: как узнать новое положение узлом |
F. Микрофон через JSONata |
то же одним узлом |
G. Переход из программы |
как программа открывает другую страницу интерфейса |
H. Звук |
как менять кнопку, ползунок и надпись по ответу процессора и как отправить уровень обратно; зачем нужна подписка |
I. ВКС |
как менять текст и цвет по состоянию звонка и заполнять список из ответа кодека |
Что получится
Интерфейс «Первая программа» состоит из трёх страниц. На главной четыре секции и кнопка «Устройства», на странице «Устройства» — ещё две секции (звук и ВКС), на странице «Подсказка» — подсказка, которую открывает программа.
Интерфейс «Первая программа» на панели: 1 — секция «Наглядно» (кнопки HDMI 1–3 и подпись «Экран»), 2 — секция «Компактно» (кнопки HDMI 1–3 и подпись «Экран председателя»), 3 — две кнопки-переключателя микрофона, 4 — кнопка «Открыть подсказку»
Что делает каждая секция:
Наглядно. Нажали «HDMI 2» — матрица подаёт вход 2 на выход 1, а в подписи «Экран» появляется «HDMI 2».
Компактно. Нажали «HDMI 2» — матрица подаёт вход 2 на выход 2, а в подписи «Экран председателя» появляется «HDMI 2». Кнопку подсвечивает программа по ответу матрицы.
Микрофон. Нажатие включает или выключает микрофон кодека ВКС. Две кнопки делают одно и то же двумя способами.
Переход. «Открыть подсказку» — программа открывает страницу «Подсказка»; кнопка «Закрыть» на ней возвращает назад.
Звук зала (страница «Устройства»). Кнопка «Звук» и ползунок громкости показывают то, что ответил звуковой процессор; надпись рядом с ползунком — уровень в децибелах. Оператор нажал кнопку или отпустил ползунок — программа отправила команду, а вид на панели поменялся по ответу.
ВКС: звонок и контакты (страница «Устройства»). Плашка по ответу кодека показывает «Нет звонка» или «Идёт разговор» на зелёном фоне. Кнопка «Контакты» заполняет список из ответа кодека, выбранный контакт появляется в надписи «Кому звоним».
Страница «Устройства» после ответов устройств, звонка нет: 1 — кнопка «Звук», 2 — ползунок громкости, 3 — надпись с уровнем в дБ, 4 — плашка звонка, 5 — список контактов
Страница «Подсказка», которую открывает программа: 1 — надпись «Эту страницу открыла программа», 2 — кнопка «Закрыть» (ссылка на главную страницу, сделана в UI-Designer)
Что нужно заранее
Контроллер с UI-Designer (редактор интерфейсов), UI-Panel (страница, на которой оператор работает с интерфейсом) и U-Logic (редактор программы управления).
Для блоков B–D — матрица видео (драйвер
avcit-phinx), для блоков E–F и I — кодек ВКС (драйверvinteo-st), для блока H — звуковой процессор (драйверTesira). Без устройств события панели всё равно приходят в программу и проверяются отладкой. Но подписи «Экран», подсветка секции 2 и всё на странице «Устройства» меняются только по ответам устройств.Интерфейс «Первая программа» на контроллере. Проще всего загрузить готовый проект, как описано в «UI-Designer»:
demo-hall.zip. В архиве три интерфейса: «Демо-зал», «Рецепты» и «Первая программа». «Загрузить проект» заменяет весь проект на контроллере, поэтому сначала сохраните свой («Скачать проект»).На вкладке U-Logic — узлы
UI - Panel inиUI - Panel outс подключением UI-listener («Первый интерфейс»). В готовой вкладке они уже есть.
Если хотите собрать интерфейс сами
В таблице — элементы интерфейса «Первая программа» (размер 1280 × 800). Имена нужно вписать в UI-Designer буква в букву: по имени (ID элемента) программа находит элемент («Связь интерфейса с программой»). Остальное оформление — на ваш вкус.
Секция |
Элемент |
Имя |
|---|---|---|
1. Наглядно |
кнопки «HDMI 1», «HDMI 2», «HDMI 3» — в одной группе «Interlock» |
|
1. Наглядно |
надпись «Экран:» и надпись-значение «—» |
|
2. Компактно |
кнопки «HDMI 1», «HDMI 2», «HDMI 3» — без группы |
|
2. Компактно |
надпись «Экран председателя:» и надпись-значение «—» |
|
3. Микрофон |
две кнопки с флажком «Отметить как toggle»: «через switch» и «через JSONata» |
|
4. Переход |
кнопка «Открыть подсказку» (без ссылки) |
|
шапка главной страницы |
кнопка «Устройства» со ссылкой на страницу «Устройства» |
|
страница «Устройства», 5. Звук зала |
кнопка-переключатель (флажок «Отметить как toggle»): в нажатом состоянии текст «Звук включён», в обычном — «Звук выключен» |
|
5. Звук зала |
горизонтальный ползунок; «Отправлять команды после» — «Отпускание» |
|
5. Звук зала |
надписи «Громкость:» и значение «—» |
|
5. Звук зала |
подписи краёв шкалы «−60 дБ» и «0 дБ» (программа их не меняет) |
|
6. ВКС: звонок и контакты |
плашка-надпись «Нет звонка» |
|
6. ВКС |
кнопки «Позвонить» и «Завершить» |
|
6. ВКС |
надпись «Кому звоним:» и значение «Выберите контакт» |
|
6. ВКС |
кнопка «Контакты» и список |
|
страница «Устройства» |
кнопка «Назад» со ссылкой на главную страницу |
|
страница «Подсказка» |
кнопка «Закрыть» со ссылкой на главную страницу |
|
Имена построены по схеме Группа_Объект_тип (_b — кнопка, _lb — надпись), поэтому секцию 2 можно поймать одним шаблоном Fp_Map_*_b. Как настроить группу «Interlock» и флажок «Отметить как toggle» — «Кнопки и состояния». Как добавить вторую страницу и ссылку — «UI-Designer» и «Первый интерфейс». Не забудьте сохранить и опубликовать интерфейс: иначе элементов не будет в списках узлов.
Группа «Interlock» в секции 1 — сознательный выбор: панель сама подсвечивает нажатую кнопку, и программа для подсветки не нужна. В секции 2 группы нет, подсветку ведёт программа по ответу матрицы: так на панели видно то, что действительно произошло.
Готовая вкладка
Если не хотите собирать программу, скачайте готовую:
first-program-flow.json— одна вкладка «Первая программа»; импортируется через меню U-Logic → «Импорт» так же, как «Демо-зал». Шаги — в разделе «Способ 2. Только поток» страницы «Программа «Демо-зал»: обзор». Особенно важен шаг 8: он про подключение «Демо: UI-Panel». Файл создаёт своё; если на контроллере такое уже есть, в узлахUI - Panel inиUI - Panel outнадо выбрать существующее;demo-hall-project.zip— проект целиком: две вкладки («Демо-зал» и «Первая программа») и четыре драйвера. «Загрузить проект» заменяет все потоки и драйверы контроллера, предупреждение — на той же странице.
После импорта впишите адреса своих устройств в подключения «Демо: матрица», «Демо: звуковой процессор» и «Демо: кодек ВКС» (меню → «Конфигурационные узлы»); кодеку ВКС укажите также логин и пароль устройства. В узлах блока H в параметрах команд стоят instanceTag DemoLevels и channel 1. Это адрес регулятора громкости зала в проекте процессора: впишите свои. Затем нажмите «Развернуть» (кнопка U-Logic, которая запускает правки программы в работу). Если вы уже загружали «Демо-зал», подключения «Демо: …» совпадут: окно импорта предложит заменить совпавшие узлы. После замены адреса нужно вписать заново.
Вкладка читается сверху вниз.
Вкладка «Первая программа», верх: 1 — блок A «Старт: карты», 2 — блок B «Наглядно: правило на кнопку», 3 — блок C «Компактно: карта входов»
Вкладка «Первая программа», середина: 1 — блок D «Ответ матрицы: надписи и подсветка», 2 — блок E «Микрофон через switch», 3 — блок F «Микрофон через JSONata», 4 — блок G «Переход из программы»
В каждом блоке свой UI - Panel in с одним и тем же подключением UI-listener: так блоки не зависят друг от друга, и их удобно читать по одному. В большой программе «Демо-зал» вход один на всю вкладку, а блоки подключены к нему парами link (см. «Программа «Демо-зал»: обзор»).
Ниже каждый блок разобран по шагам: зачем он нужен, какие узлы и что в их окнах, что вы увидите, как проверить.
Как проверять: узел debug
Прежде чем разбирать блоки, запомните один приём: чтобы увидеть, что лежит в сообщении, подключите к выходу нужного узла узел debug. В его окне в поле «Выводить» выберите «весь msg объект сообщения», нажмите «Готово» и «Развернуть». Затем откройте на правой боковой панели вкладку отладки (значок «жук») и нажмите кнопку на панели: в отладке появится сообщение, в нём можно развернуть payload, parameters и другие поля. После проверки узел debug можно отключить кнопкой справа от него или удалить.
Блок A. Старт: карты
Зачем. Программе нужны таблицы соответствий: «какая кнопка — какой вход матрицы», «какой вход — какое название». Эти таблицы записывают один раз при запуске в память программы, а все остальные узлы только читают их. Блок A делает эту запись. Блок B таблиц не использует, а блоки C и D без блока A работать не будут.
Что такое «память программы». У программы есть переменные, которые живут, пока она запущена, и видны узлам. Они бывают двух видов, и в списках типов в окне узла они называются flow. и global.:
flow.— переменная вкладки: её видят только узлы той же вкладки. Так сделано в «Демо-зале»;global.— глобальная переменная: её видят все узлы всех вкладок. Так сделано в «Первой программе».
Значением переменной может быть число, строка или целая таблица (объект JSON). Здесь хранятся таблицы: ключ — имя нажатой кнопки или номер входа, значение — то, что нужно отправить или показать.
Примечание
Переменные хранятся в памяти и пропадают при перезапуске программы. Поэтому таблицы записывает узел, который срабатывает при запуске, а не вы вручную. Если вы изменили таблицу, нажмите «Развернуть» и запустите узел inject кнопкой слева от него — иначе в памяти останется старая.
Шаги.
Перетащите на вкладку узел
inject. Откройте его. В поле «Имя» впишите «При запуске». Включите отметку «Отправить через» и впишите1(«Отправить через 1 сек, затем» — запуск один раз после старта). Что именно он отправляет (по умолчанию — метку времени), неважно: он нужен только как «пускатель». Нажмите «Готово».Перетащите узел
changeи соедините с ним выходinject.Откройте
changeи в поле «Имя» впишите «Карты кнопок и входов». Нажмите «добавить» под списком «Правила» и задайте правило: «Установить», в первом списке выберитеglobal., впишите имяfpInputs. В строке «to the value» выберите «JSON» и впишите таблицу «кнопка → параметры матрицы»:{"Fp_Map_Hdmi1_b": {"input": 1, "output": 2}, "Fp_Map_Hdmi2_b": {"input": 2, "output": 2}, "Fp_Map_Hdmi3_b": {"input": 3, "output": 2}}
Нажмите «добавить» ещё раз и задайте второе правило: «Установить»
global.fpTitles, «JSON»: таблица «вход → название»{"1": "HDMI 1", "2": "HDMI 2", "3": "HDMI 3"}
Нажмите «добавить» и задайте третье правило: «Установить»
global.fpButtons, «JSON»: таблица «вход → имя кнопки»{"1": "Fp_Map_Hdmi1_b", "2": "Fp_Map_Hdmi2_b", "3": "Fp_Map_Hdmi3_b"}
Нажмите «Готово» и «Развернуть».
Окно узла inject «При запуске»: 1 — отметка «Отправить через» и задержка 1 секунда
Окно узла change «Карты кнопок и входов»: 1 — правило «Установить» global.fpInputs, 2 — правило global.fpTitles, 3 — правило global.fpButtons
Что вы увидите. Ничего на панели: блок A только готовит данные. Работу блока вы проверите в блоке C: если msg.parameters там получил значение из таблицы, значит, таблица записана.
Блок B. Наглядно: правило на кнопку
Зачем. Это самый понятный способ: на каждую кнопку — своё правило в ui - switch и свой узел change с готовыми параметрами команды. Читается сразу: кнопка «HDMI 2» → вход 2 → выход 1. Подходит, когда кнопок две-три. Когда их десять, лучше компактный способ из блока C.
Цепочка блока: UI - Panel in → ui - switch (три выхода) → три узла change → один device - command.
Шаги.
Перетащите
UI - Panel in(если его ещё нет; «Имя» — «События панели») и соедините с нимui - switch.Откройте
ui - switch. В «Имя узла» впишите «Кнопки HDMI: по правилу». В «Интерфейс» выберите «Первая программа». В «Правила маршрутизации» добавьте три правила: элементFp_Hdmi1_b,Fp_Hdmi2_bиFp_Hdmi3_b, у каждого событиеpush. Нажмите «Готово». У узла три выхода. Подробно про правила — «Приём событий».К каждому выходу подключите свой узел
change. Назовите их в поле «Имя» «HDMI 1 → экран», «HDMI 2 → экран» и «HDMI 3 → экран». В первом нажмите «добавить» и задайте правило «Установить», в первом списке выберитеmsg., впишитеparameters. В строке «to the value» выберите «JSON» и впишите{"input": 1, "output": 1}. Во втором —{"input": 2, "output": 1}, в третьем —{"input": 3, "output": 1}. Здесьinput— номер входа матрицы,output— номер выхода (1 — экран зала).Перетащите
device - command(«Имя» — «Матрица: подать вход») и соедините с ним выходы всех трёхchange. В окне выберите «Соединение» — подключение к вашей матрице («Демо: матрица») и в «Команда» —route. Нажмите «Готово».Нажмите «Развернуть».
Окно узла ui - switch «Кнопки HDMI: по правилу»: 1 — «Интерфейс», 2 — три правила по одному на кнопку (Fp_Hdmi1_b, Fp_Hdmi2_b, Fp_Hdmi3_b), 3 — событие push
Окно узла change «HDMI 2 → экран»: 1 — правило «Установить» msg.parameters, 2 — тип «JSON» и значение {"input": 2, "output": 1}
Что вы увидите. Нажмите на панели «HDMI 2»: кнопка сразу станет подсвеченной (подсветку делает группа «Interlock» в самом интерфейсе), а матрица получит команду «вход 2 на выход 1». Подпись «Экран» поменяется чуть позже — когда матрица ответит (блок D).
Как проверить. Подключите debug («весь msg объект сообщения») к выходу узла change «HDMI 2 → экран» и нажмите «HDMI 2». В отладке: msg.parameters — { input: 2, output: 1 }. Если ничего не пришло, подключите debug к выходу ui - switch: там должен быть payload.object = Fp_Hdmi2_b.
Блок C. Компактно: карта входов
Зачем. Если кнопок много, на каждую заводить правило и узел change — утомительно и легко ошибиться. Решение: одно правило на все кнопки (по шаблону имени) и одна таблица «кнопка → параметры», которую записал блок A. Узел change по имени нажатой кнопки достаёт из таблицы нужные параметры. Если добавить четвёртую кнопку, достаточно дописать строку в таблицу, остальное не меняется.
Цепочка: UI - Panel in → ui - switch (одно правило по шаблону) → change → тот же device - command «Матрица: подать вход».
Шаги.
Добавьте ещё один
UI - Panel in(«Имя» — «События панели») и соедините с нимui - switch.Откройте
ui - switch. В «Имя узла» впишите «Кнопки HDMI: по шаблону». В «Интерфейс» выберите «Первая программа». Добавьте правило, включите флажок «Шаблон», впишитеFp_Map_*_b, выберите режимwildcard (*, ?)и событиеpush. Нажмите «Готово». Теперь любая кнопка, имя которой начинается сFp_Map_и заканчивается_b, попадёт в этот выход.Подключите узел
change(«Имя» — «Кнопка → параметры по карте»). Нажмите «добавить» и задайте правило: «Установить»msg.parameters. В строке «to the value» выберите типglobal.и впишитеfpInputs[msg.payload.object]. Под значением включите флажок «Deep copy value» («глубокая копия»). Нажмите «Готово».Соедините выход
changeсо входом того жеdevice - command, что в блоке B (второйdevice - commandне нужен: одна матрица — один узел).Нажмите «Развернуть».
Окно узла ui - switch «Кнопки HDMI: по шаблону»: 1 — «Интерфейс», 2 — шаблон Fp_Map_*_b с флажком «Шаблон», 3 — режим wildcard (*, ?), 4 — событие push
Окно узла change «Кнопка → параметры по карте»: 1 — «Установить» msg.parameters, 2 — значение берётся из global. по ключу fpInputs[msg.payload.object], 3 — флажок «Deep copy value»
Как это работает
Выражение fpInputs[msg.payload.object] по частям:
fpInputs— имя переменной в памяти: таблица, которую записал блок A. Это строки вида «имя кнопки: параметры».В квадратных скобках — ключ: какую строку таблицы взять. Ключ узел вычисляет сам из сообщения:
msg.payload.object— это имя нажатой кнопки, оно пришло с панели и лежит в сообщении послеui - switch(в отладке вы видели его какobject).Значит, нажали
Fp_Map_Hdmi2_b→ ключ равен"Fp_Map_Hdmi2_b"→ из таблицы берётся{"input": 2, "output": 2}→ оно записывается вmsg.parameters. Аdevice - commandподставляетmsg.parametersв командуroute.
Вот почему имя элемента в UI-Designer должно совпадать до буквы с ключом в таблице: ключ — это и есть имя элемента.
Зачем «глубокая копия». Без неё в сообщение попадёт не сама строка таблицы, а ссылка на неё в памяти. Если дальше по цепочке какой-то узел допишет или изменит msg.parameters, изменится и таблица в памяти — для всех следующих нажатий. С флажком сообщение получает свою копию, и таблица остаётся прежней. Включайте флажок всегда, когда берёте из памяти таблицу или список целиком.
Что вы увидите. Нажмите «HDMI 3» в секции 2: матрица получает «вход 3 на выход 2». Кнопка на панели пока не подсветится — подсветка придёт по ответу матрицы (блок D). Повторите нажатие несколько раз: таблица в памяти не портится.
Как проверить. Подключите debug к выходу change: msg.parameters — { input: 3, output: 2 }. Если там undefined — ключа нет в таблице: проверьте, что блок A развёрнут и запущен, и что имя кнопки совпадает с ключом.
Блок D. Ответ матрицы: надписи и подсветка
Зачем. Нажатие — это только намерение. Команда могла не дойти, матрицу могли переключить с пульта. Поэтому подписи и подсветку лучше менять по ответу устройства, как бы оно ни было переключено: на панели видно то, что произошло на самом деле. Блок D принимает ответ матрицы и раскладывает его: выход 1 — надпись «Экран», выход 2 — «Экран председателя» и подсветка кнопок секции 2.
Цепочка: device - response - listener → switch «Подтверждено?» → switch «Какой выход?» → узлы change → api - helper - 2 и interlock - 2 → UI - Panel out.
Шаги.
Перетащите
device - response - listener(«Имя» — «Матрица: ответы»). «Соединение» — то же, что уdevice - command(матрица). «Выходы» — 2. В «Типы ответов» отметьтеrouteи выберите для него «Выход 2» (первый выход останется для прочего). Нажмите «Готово». Подробнее — «Команды устройствам и ответы».К «Выходу 2» подключите
switch«Подтверждено?»: свойствоmsg.payload.ack, одно правило «равно true». Драйвер матрицы сообщает об операции дважды: когда команда отправлена (ack: false) и когда матрица ответила (ack: true). Нужен только второй ответ: он и есть факт. Первый этотswitchотбрасывает, иначе надпись обновилась бы раньше, чем матрица что-то сделала.Подключите второй
switch«Какой выход?». Свойство —msg.payload.output, два правила «==» (число):1и2. Это фильтр ответа: ответ несёт номер выхода, который переключился, и по нему узел решает, куда направить ответ.С выхода 1 («экран») подключите
change«Вход → название экрана»: два правила «Установить». Первое —msg.topicкак «JSON»{}(пустой объект). Второе —msg.topic.Fp_Screen_val_lb, значение типаglobal.—fpTitles[msg.payload.input]. Так вmsg.topicполучается запись{"Fp_Screen_val_lb": "HDMI 2"}: «имя надписи → её текст». Дальше подключитеapi - helper - 2«Надпись: экран»: «Интерфейс» — «Первая программа». В «Объекты управления» добавлен элементFp_Screen_val_lbс событием «Текст». «Источник входных данных» оставлен по умолчанию (msg.topic). Подробно об этом узле — «Изменение вида на панели».С выхода 2 («председатель») подключите две ветки.
Название: такой же
change«Вход → название председателя» (msg.topic.Fp_Chair_val_lb) иapi - helper - 2«Надпись: председатель» с элементомFp_Chair_val_lb.Подсветка:
change«Вход → кнопка»: «Установить»msg.payload, значение типаglobal.—fpButtons[msg.payload.input]. Это имя кнопки секции 2, которая соответствует номеру входа в ответе. Затемinterlock - 2«Подсветка: карта входов»: «Интерфейс» — «Первая программа», «Тип события» —uiState, «Активное состояние» —selected, «Состояние по умолчанию» —default, «Источник входных данных» —msg.payload. В «Список кнопок» через «Кнопки интерфейса» и «Добавить» добавьте три кнопкиFp_Map_Hdmi1_b,Fp_Map_Hdmi2_b,Fp_Map_Hdmi3_b. Узел подсвечивает ту, чьё имя пришло, остальные гасит.
Выходы всех
api - helper - 2иinterlock - 2соедините сUI - Panel out(«Имя» — «Команды панели»). Нажмите «Развернуть».
Окно узла switch «Какой выход?»: 1 — свойство msg.payload.output, 2 — правило «== 1» (экран, выход 1 узла), 3 — правило «== 2» (экран председателя, выход 2 узла)
Зачем фильтр «Какой выход?». Матрица одна на несколько выходов. Допустим, вы нажали в секции 2 «HDMI 1» — матрица ответила «выход 2 ← вход 1». Если не проверить номер выхода, этот ответ изменил бы и надпись «Экран»: ведь выход 2 к залу отношения не имеет. Выход 2 в нашем интерфейсе — экран председателя; обычный switch по номеру выхода направляет ответ в нужную ветку. Ответ по выходу, которого нет среди правил, не пойдёт никуда. Тот же приём стоит в «Демо-зале»: там выход 1 — экран зала, и ответы по другим выходам отброшены.
Что вы увидите. Нажмите в секции 1 «HDMI 2»: через мгновение «Экран:» покажет «HDMI 2». Нажмите в секции 2 «HDMI 3»: «Экран председателя:» покажет «HDMI 3», кнопка «HDMI 3» подсветится, остальные в секции 2 погаснут, а «Экран:» не изменится.
Как проверить. Подключите debug к выходу «Подтверждено?»: после нажатия там одно сообщение с payload.ack: true, payload.output и payload.input. Нет сообщения — ответ матрицы не дошёл: проверьте «Соединение» и тип ответа route в device - response - listener.
Блок E. Микрофон через switch
Зачем. Кнопка-переключатель (микрофон, звук) сама меняет вид на панели, а программе нужно узнать новое положение и отправить устройству «включить» или «выключить». Положение приходит событием value_changed.
Что приходит в программу, если нажать переключатель: сначала push, release, tap (как у любой кнопки), а следом — value_changed с полем value. При включении value равно "pressed" (кнопка нажата), при выключении — "default" (кнопка вернулась в обычное состояние). Поэтому в правиле ui - switch выбирают именно value_changed.
Цепочка: UI - Panel in → ui - switch → switch «Нажата?» → два change → device - command.
Шаги.
Добавьте
ui - switch(«Имя узла» — «Микрофон: через switch»): «Интерфейс» — «Первая программа», правило наFp_MicSwitch_b, событиеvalue_changed.Добавьте
switch«Нажата?»: свойствоmsg.payload.value, два правила «==» (строка):pressedиdefault.К выходу
pressedподключитеchange«Микрофон: включить»: два правила «Установить»:msg.command— «строка»setMute;msg.parameters— «JSON»{"mute": false}. К выходуdefaultподключитеchange«Микрофон: выключить»: то же, но{"mute": true}. Здесьmute— «звук отключён»: нажатая кнопка (зелёная, значок микрофона) означает, что микрофон включён.Оба
changeсоедините сdevice - command(«Имя» — «Кодек: микрофон»): «Соединение» — кодек ВКС. В поле «Команда» выберитеsetMute(поле обязательно; ту же команду задаётmsg.command).Нажмите «Развернуть».
Окно узла switch «Нажата?»: 1 — свойство msg.payload.value, 2 — правило «== pressed» (строка), 3 — правило «== default» (строка)
Что вы увидите. Нажали «через switch» — кнопка зелёная, значок микрофона без перечёркивания, кодек получил setMute с mute: false. Нажали снова — кнопка белая, значок перечёркнут, кодек получил mute: true. Одна команда на нажатие.
Как проверить. Подключите debug к выходу ui - switch: на каждое нажатие по правилу придёт одно сообщение value_changed (не три). Подключите debug к «Нажата?»: сообщение выйдет из верхнего или нижнего выхода в зависимости от положения.
Блок F. Микрофон через JSONata
Зачем. Тот же микрофон, но короче: один узел change вместо switch и двух change. Здесь пригодится JSONata.
Что такое JSONata. Это короткий язык выражений: вы пишете формулу, а узел вычисляет её над сообщением и подставляет результат. Формула видит сообщение как набор полей: payload.value — это то же, что msg.payload.value. В окне узла change JSONata выбирается типом значения «выражение» (рядом со «строка», «JSON» и другими).
Шаги.
Добавьте
ui - switch(«Имя узла» — «Микрофон: через JSONata»): правило наFp_MicJsonata_b, событиеvalue_changed.Добавьте один
change(«Имя» — «setMute по JSONata») с двумя правилами «Установить» (кнопка «добавить»):msg.command— «строка»setMute;msg.parameters— тип «выражение», значение
{"mute": payload.value = "default"}Соедините
changeсdevice - command«Кодек: микрофон (JSONata)» (то же подключение — кодек ВКС). Это второй узел команды для того же кодека: блоки E и F — два независимых учебных варианта, и у каждого свой узел; в вашей программе хватит одного.Нажмите «Развернуть».
Окно узла change «setMute по JSONata»: 1 — правило msg.command (строка setMute), 2 — правило msg.parameters с типом «выражение», 3 — выражение {"mute": payload.value = "default"}
Разбор выражения {"mute": payload.value = "default"}:
{ … }— фигурные скобки создают объект: пары «имя: значение», как в JSON. Результат — объект, который уйдёт вmsg.parameters."mute":— имя поля, которое ждёт командаsetMute.payload.value— значение, которое пришло от кнопки:"pressed"или"default".= "default"— сравнение: «равно ли это значение"default"?». Результат —trueилиfalse.
Итого: пришло "default" (кнопку выключили) → {"mute": true}; пришло "pressed" (включили) → {"mute": false}. Одно выражение заменило switch и два change блока E.
Что вы увидите. Те же действия, что в блоке E: нажали — микрофон включён, нажали ещё раз — выключен, кодек получает по одной команде на нажатие.
Что выбрать. switch нагляднее и подойдёт, когда на каждое положение нужны разные действия. Выражение короче, когда различие только в одном значении. Работают обе записи.
Блок G. Переход из программы
Зачем. Иногда страницу должна открыть программа: по результату проверки, по событию устройства. Для этого есть тип «navigation» в api - helper - 2. Ограничение: он открывает только страницы интерфейса по имени. Оверлей (отдельная «подстраница» со своим холстом) во фрейме (область на странице, в которой показан оверлей) программа показывает другим способом — событием «Overlay» того же узла; см. «Сменить оверлей во фрейме».
Цепочка: UI - Panel in → ui - switch → api - helper - 2 (navigation) → UI - Panel out.
Шаги.
Добавьте
ui - switch(«Имя узла» — «Открыть подсказку»): правило наFp_Open_b, событиеpush.Добавьте
api - helper - 2(«Имя узла» — «Перейти: Подсказка»): «Интерфейс (UI)» — «Первая программа»; «Тип сообщения» —navigation. Ниже «Объектов управления» появятся поля «Поиск:» и «Страница:»: найдите и выберите страницу «Подсказка». Входные данные для этого типа не нужны: узел срабатывает на любое сообщение.Выход соедините с
UI - Panel out(«Имя» — «Команды панели»). Нажмите «Развернуть».
Окно узла api - helper - 2 «Перейти: Подсказка»: 1 — «Интерфейс (UI)», 2 — «Тип сообщения» navigation, 3 — «Страница:» «Подсказка»
Что вы увидите. Нажали «Открыть подсказку» — на панели вместо главной страницы открылась «Подсказка». «Закрыть» вернуло главную: эта кнопка — ссылка из UI-Designer, программа для возврата не нужна.
Как проверить. Подключите debug к выходу api - helper - 2: после нажатия придёт сообщение, в котором есть имя страницы «Подсказка». Нет перехода — смотрите «Частые ошибки» ниже.
Блок H. Звук
Зачем. Блоки B–D показали путь «нажали → команда → ответ → подпись» для матрицы. Здесь тот же путь для звукового процессора, но с двумя новыми приёмами. Первый — ползунок: число из ответа превращается в положение ручки и подпись, а положение ручки — обратно в команду в децибелах. Второй — подписка: процессор присылает ответы только тем, кто об этом попросил. Что приходит от процессора, как устроены выражения и окно api - helper - 2 — пошагово в «Изменении вида на панели», примеры 1 и 2; здесь — как собрать блок целиком.
Блок состоит из трёх групп на вкладке: «5. Звук: кнопка и ползунок → процессор» (команды), «Звук: подписка на ответы процессора» и «Звук: ответ процессора → кнопка и ползунок». Цифра 5 в названии первой группы — номер секции интерфейса, а не блока: так же 6 в названии первой группы блока I.
Вкладка целиком, блок «Звук»:
Блок H «Звук» на вкладке (в кадре также группа подписки): 1 — ui - switch «Звук: кнопка и ползунок», 2 — change «Громкость: 0…1 → дБ», 3 — device - response - listener «Звук: ответы», 4 — switch «Какая подписка?», 5 — change «Уровень → ползунок и надпись», 6 — api - helper - 2 «Громкость: ползунок и надпись»
Группа 1. Команды: кнопка и ползунок → процессор
Цепочка: UI - Panel in → ui - switch (два выхода) → два change → device - command.
Шаги.
Перетащите
UI - Panel in(«Имя» — «События панели») и соедините с нимui - switch(«Имя узла» — «Звук: кнопка и ползунок»). В «Интерфейс» выберите «Первая программа». Добавьте два правила:Fp_Mute_bс событиемvalue_changed(выход 1) иFp_Vol_slс событиемslide_end(выход 2). КнопкаFp_Mute_b— переключатель, как микрофон в блоках E и F, поэтому для неё выбраноvalue_changed.slide_endприходит один раз, когда оператор отпустил ручку. Поле «Отправлять команды после» у ползунка должно стоять в положении «Отпускание» («Элементы интерфейса»).К выходу 1 подключите
change«Звук: mute по кнопке» с двумя правилами «Установить»:msg.command— «строка»setMute;msg.parameters— «выражение» (в окнеchangeэтот тип отмечен значкомJ:перед полем; слово «выражение» видно только в меню выбора типа):{"instanceTag": "DemoLevels", "channel": 1, "state": payload.value = "default"}Это тот же приём, что в блоке F:
payload.value—"pressed"или"default", а сравнение= "default"даётtrue, когда кнопка стала обычной («Звук выключен»).state— «включить ли mute»;instanceTagиchannel— адрес регулятора в процессоре.К выходу 2 подключите
change«Громкость: 0…1 → дБ»:msg.command— «строка»setLevel;msg.parameters— «выражение»{"instanceTag": "DemoLevels", "channel": 1, "level": $round(payload.value * 60 - 60)}. Что значит это выражение — в «Изменении вида на панели», пример 2, раздел «Обратное направление».Оба
changeсоедините сdevice - command(«Имя» — «Звук: команда»): «Соединение» — «Демо: звуковой процессор», «Команда» —setMute(обязательное поле; нужную команду задаётmsg.command).
Группа 2. Подписка на ответы процессора
Зачем подписка. Нажатие на панели — это просьба к процессору. Но состояние звука и уровня может поменяться и без этой панели: другой панелью, пультом, сценарием. Процессор сам об этом не рассказывает, пока его не попросят. Подписка — просьба, которую программа отправляет один раз: «присылай мне новое значение этого параметра каждый раз, когда оно меняется, и называй его вот так». Название подписки приходит в каждом ответе (поле publishToken). По нему программа потом понимает, что это за ответ. Здесь две подписки: fpHallMute — звук включён или выключен, и fpHallLevel — уровень.
Когда подписываться и почему пауза. Подписка живёт, пока работает связь с процессором. Связь может прерваться и подняться снова, поэтому подписку отправляют каждый раз после подключения, а не один раз при запуске программы. Но сразу после сообщения «подключился» связь ещё не готова принимать команды, и первая же команда может потеряться. Поэтому между «подключился» и подпиской ставят паузу 2 секунды. Пока подписки нет, панель не узнает об ответах процессора: на странице «Устройства» останется то, что задано в UI-Designer («—», «Нет звонка»).
Цепочка: device - command «Звук: команда» (первый выход) → switch «Подключился?» → delay «Пауза 2 с» → два change → device - command «Звук: подписаться». Дополнительно — inject «При запуске»: при запуске программы подписка тоже должна уйти, а связь к тому времени уже может быть установлена.
Шаги.
Первый выход
device - command«Звук: команда» (состояние соединения) подключите кswitch«Подключился?»: свойствоmsg.payload.status, одно правило «==» (строка)connected. Остальные состояния (disconnected,error) он отбрасывает.Выход
switchподключите кdelay(«Имя» — «Пауза 2 с»): «Действие» — «Задержка каждого сообщения», «Фиксированная задержка» — 2 секунды.Добавьте
inject(«Имя» — «При запуске»): «Отправить через» — 3 секунды, один раз после запуска. Его выход и выходdelayподключите к двум узламchangeодновременно.Добавьте
change«Подписка: mute зала»: правило «Установить»msg.parameters, тип «JSON»:{"instanceTag": "DemoLevels", "attribute": "mute", "channel": 1, "subscriptionName": "fpHallMute", "minInterval": 0}
Добавьте
change«Подписка: громкость зала» — то же, но"attribute": "level","subscriptionName": "fpHallLevel","minInterval": 200.Оба
changeподключите кdevice - command(«Имя» — «Звук: подписаться»): «Соединение» — «Демо: звуковой процессор», «Команда» —subscribe.
Что значат поля подписки:
attribute— что отслеживать (mute— звук,level— уровень);instanceTagиchannel— какой регулятор;subscriptionName— как назвать подписку (имя придёт в ответе какpublishToken; выберите имя, которое не используют другие подписки на том же процессоре);minInterval— не чаще одного уведомления за столько миллисекунд (0 — без ограничения).
Для уровня стоит 200: ползунок не будет «дрожать», когда уровень меняется быстро.
Группа «Звук: подписка на ответы процессора»: 1 — switch «Подключился?», 2 — delay «Пауза 2 с», 3 — inject «При запуске», 4 — change «Подписка: mute зала» и «Подписка: громкость зала», 5 — device - command «Звук: подписаться»
Группа 3. Ответ процессора → кнопка и ползунок
Цепочка: device - response - listener → switch «Какая подписка?» → два change → два api - helper - 2 → UI - Panel out.
Шаги.
Добавьте
device - response - listener(«Имя» — «Звук: ответы»): «Соединение» — «Демо: звуковой процессор», «Выходы» — 2. В «Типы ответов» отметьтеsubscribeNotificationи выберите «Выход 2».К «Выходу 2» подключите
debug(«Имя» — «Что прислал процессор», «Выводить» —msg.payload; он выключен, пока вы не проверяете) иswitch«Какая подписка?» (свойствоmsg.payload.publishToken, правилаfpHallMuteиfpHallLevel).Выход
fpHallMute→change«Mute → вид кнопки» →api - helper - 2«Кнопка: звук зала». ВыходfpHallLevel→change«Уровень → ползунок и надпись» →api - helper - 2«Громкость: ползунок и надпись». Выражения, поля и карточки — «Изменение вида на панели», примеры 1 и 2.Выходы обоих
api - helper - 2соедините сUI - Panel out(«Имя» — «Команды панели»). Нажмите «Развернуть».
Окно узла device - response - listener «Звук: ответы»: 1 — «Соединение», 2 — «Выходы» (2), 3 — тип ответа subscribeNotification и «Выход 2»
Что вы увидите. Откройте на панели страницу «Устройства» (кнопка «Устройства» на главной). Через несколько секунд после запуска кнопка «Звук» и ползунок показывают то, что сейчас выставлено на процессоре, а надпись «Громкость:» — уровень в дБ. Нажмите «Звук»: процессор получает setMute, присылает уведомление fpHallMute, кнопка принимает вид по этому ответу. Подвиньте ручку и отпустите: процессор получает setLevel, присылает fpHallLevel, ручка и надпись встают по ответу. Измените звук или уровень на самом процессоре — панель последует за ним.
Как проверить. Включите debug «Что прислал процессор» и откройте боковую панель отладки. Сразу после запуска (через 3 секунды, а после переподключения — через 2) придут два сообщения: fpHallMute и fpHallLevel. Не пришли — подписка не ушла: проверьте статус device - command «Звук: команда» (подключён ли процессор), instanceTag и канал в параметрах и switch «Подключился?» (отладка за ним). Сообщение пришло, а вид не поменялся — отладка за change покажет, что лежит в msg.topic.
Блок I. ВКС
Зачем. Тот же принцип для кодека видеоконференцсвязи: состояние звонка (текст и цвет плашки) и список контактов приходят в ответах кодека. Блок учит ещё двум вещам: как поменять два свойства одного элемента одним сообщением и как превратить массив из ответа в строки списка выражением change. Разбор ответов и выражений — «Изменение вида на панели», примеры 3 и 4.
Блок состоит из двух групп: «6. ВКС: кнопки и список → кодек» (команды) и «ВКС: ответы кодека → надпись и список».
Вкладка целиком, блок «ВКС»:
Блок I «ВКС» на вкладке: 1 — ui - switch «ВКС: кнопки и список», 2 — change «Строка → кому звоним», 3 — device - response - listener «Кодек: ответы», 4 — change «Контакты → строки списка», 5 — change «Звонок → текст и цвет», 6 — api - helper - 2 «Надпись: звонок»
Группа 1. Кнопки и список → кодек
Цепочка: UI - Panel in → ui - switch (четыре выхода) → change и switch → device - command и api - helper - 2.
Шаги.
Соедините
UI - Panel inсui - switch(«Имя узла» — «ВКС: кнопки и список»). Четыре правила:Fp_Contacts_bс событиемpush(выход 1),Fp_Contacts_lsс событиемitem_selected(выход 2),Fp_Call_bс событиемpush(выход 3),Fp_Hangup_bс событиемpush(выход 4).Выход 1 →
change«Команда: адресная книга»:msg.command— «строка»getContacts. Он идёт вdevice - command«Кодек: команда» («Соединение» — «Демо: кодек ВКС», «Команда» —getContacts).Выход 2 →
change«Строка → кому звоним» иapi - helper - 2«Надпись: кому звоним» (разбор — в примере 4 страницы «Изменение вида на панели»): номер выбранного контакта запоминается в памяти программы, а в надписиFp_Target_val_lbпоявляется имя контакта.Выход 3 →
switch«Контакт выбран?» (свойство —global.fpNumber, правило «не равно null»: пока контакт не выбран, звонить некому) →change«Команда: позвонить»:msg.command— «строка»dial,msg.parameters.number— значение типаglobal.fpNumber. Выход идёт в тот жеdevice - command«Кодек: команда».Выход 4 →
change«Команда: завершить» (msg.command— «строка»hangup) → тот жеdevice - command.
Группа 2. Ответы кодека → надпись и список
Цепочка: inject → device - command (запрос состояния); device - response - listener → два change → два api - helper - 2 → UI - Panel out.
Шаги.
Кодек о звонке сам не сообщает, поэтому его спрашивают. Добавьте
inject(«Имя» — «Раз в 3 с»): в списке «Повторять» выберите «с интервалом», впишите3и единицы «сек», а отметку «Отправить через» — 5 секунд после запуска. Подключите его кdevice - command(«Имя» — «Кодек: состояние звонка»): «Соединение» — «Демо: кодек ВКС», «Команда» —getCallInfo.Добавьте
device - response - listener(«Имя» — «Кодек: ответы»): «Соединение» — «Демо: кодек ВКС», «Выходы» — 3. В «Типы ответов» отметьтеcontacts— «Выход 2» иcallInfo— «Выход 3»; первый выход остаётся для прочих ответов.К каждому из выходов 2 и 3 подключите
debug«Что прислал кодек» (общий для обоих выходов; выключен, пока вы не проверяете).«Выход 2» →
change«Контакты → строки списка» →api - helper - 2«Список контактов».«Выход 3» →
change«Звонок → текст и цвет» →api - helper - 2«Надпись: звонок».Выходы обоих
api - helper - 2соедините сUI - Panel out(«Команды панели»). Нажмите «Развернуть».
Окно узла device - response - listener «Кодек: ответы»: 1 — «Соединение», 2 — «Выходы» (3), 3 — тип contacts и «Выход 2», 4 — тип callInfo и «Выход 3»
Что вы увидите. На странице «Устройства» нажмите «Контакты»: в списке появятся контакты из адресной книги кодека. Выберите строку: в надписи «Кому звоним» — имя контакта. Нажмите «Позвонить»: кодек набирает номер, и в течение 3 секунд плашка меняется с «Нет звонка» на «Идёт разговор» на светло-зелёном фоне. Нажмите «Завершить»: плашка снова «Нет звонка». Позвоните или завершите звонок с самого кодека — плашка поменяется так же: вид ведёт ответ, а не нажатие.
Как проверить. Включите debug «Что прислал кодек»: раз в 3 секунды приходит callInfo с полем inCall, на «Контакты» — contacts со списком list. Нет callInfo — проверьте подключение к кодеку и inject «Раз в 3 с». callInfo есть, а плашка не меняется — отладка за change «Звонок → текст и цвет» покажет, что лежит в msg.topic.
Что дальше
Вы собрали все основные приёмы. Дальше:
как устроены правила
ui - switchи какие бывают события — «Приём событий»;как менять кнопки, ползунки, надписи, цвета и списки по ответам устройств — «Изменение вида на панели»;
как отправлять команды и принимать ответы — «Команды устройствам и ответы»;
переключатели и группы — «Переключатели и группы»;
все приёмы в одной большой программе — «Программа «Демо-зал»: обзор».
Частые ошибки
Общий маршрут проверки по цепочке «панель → программа → устройство → панель» — на странице «Не работает: где смотреть».
На панели только точки загрузки. В программе нет развёрнутого
UI - Panel in(или не нажато «Развернуть»). Создайте в поле Path подключение UI-listener с путём/web-client, нажмите «Готово» и «Развернуть», обновите страницу панели («Первый интерфейс»). Если в селекторе нет нужного интерфейса, проект не опубликован.Нажимаю кнопку — ничего не происходит. Подключите
debugк выходуUI - Panel in: приходит ли событие? Если приходит, смотрите выход нужного правилаui - switch. Если нет — не выбран «Интерфейс» в узле, имя элемента отличается от имени в правиле хоть на букву, или интерфейс не опубликован.Действие выполняется три раза. В правиле оставлено «Любое событие»; выберите
push(одно нажатие — три события:push,release,tap).В
msg.parametersлежитundefined(блок C). Блок A не развёрнут или не запускался, либо ключа нет в таблице. Запуститеinjectкнопкой слева от него и проверьте имя кнопки.Таблица «портится» после нескольких нажатий. Не включена «глубокая копия» в
change: следующие узлы меняют ту же таблицу в памяти.Подписи «Экран» не меняются. Ответ матрицы не дошёл до блока D (нет «Соединения» или типа
route) или отброшен:switch«Подтверждено?» пропускает только ответ сack: true, а «Какой выход?» — только выходы 1 и 2.«Экран» поменялся, хотя нажимали секцию 2. Нет фильтра «Какой выход?» или он пропускает ответ в неправильную ветку.
Кнопка секции 2 не подсвечивается. На вход
interlock - 2должна прийти строка с именем кнопки: проверьтеchange«Вход → кнопка» и список кнопок в узле. Пока группы «Interlock» в интерфейсе нет, подсвечивает только программа.Переключатель шлёт команду дважды или не шлёт. В правиле выбрано
pushвместоvalue_changed; или кнопка не отмечена как toggle в UI-Designer; или она входит в группу «Interlock» — у такой кнопкиvalue_changedне приходит.Переход на «Подсказку» не работает. В узле не выбрана «Страница:» или выбран другой интерфейс. Перейти можно только на страницу; оверлей показывают событием «Overlay» («Изменение вида на панели»). Кроме того, не кладите объект в
msg.topicперед этим узлом: по умолчанию он читает входные данные оттуда.Команда не доходит. Не выбрано «Соединение» в
device - command(статус «Не настроено соединение») или устройство ещё не подключилось.Страница «Устройства» пустая: «Нет звонка» и «—». Ответы устройств не доходят. Подключите
debug(«Что прислал процессор» или «Что прислал кодек») и посмотрите, приходят ли ответы. Для звука — выполнена ли подписка: узел «Звук: команда» должен быть подключён к процессору, а после запуска и после каждого подключения через 2 секунды уходят подписки.Ответ приходит, а ползунок и кнопка не меняются. В
switch«Какая подписка?» не совпало имя подписки (fpHallMute,fpHallLevel) с тем, что написано вchangeподписки; или имя элемента в выраженииchangeотличается от имени в UI-Designer.Ползунок стоит не там. Min и Max в карточке
api - helper - 2не совпадают с диапазоном громкости (−60…0) или числа в выражении «Громкость: 0…1 → дБ» не такие же.Плашка звонка меняется с задержкой. Кодек сам о звонке не сообщает: программа спрашивает его раз в 3 секунды. Это нормально.
«Позвонить» ничего не делает. Контакт не выбран: правило «не равно null» в
switch«Контакт выбран?» не пропускает сообщение, пока в памяти нет номера. Сначала нажмите «Контакты» и выберите строку.Изменения не действуют. Правки узлов работают после «Развернуть».