Идеи озвучить кабинет сисадмина или «Умный дом», в том числе удалённый,  посещали меня давно. Поиски в Интернет, однако, не приводили к успеху, так как аппаратные решения для таких задач, как выяснилось, стоят не малых денег (например, 2N SIP AUDIO Converter и замещающие его аналоги), а софтверные (например, Net Speakerphone) не столь надежны при удаленном использовании и требуют наличия ПК на «другом конце». Впрочем один опыт софтверной интеграции с роутером по звуку у меня был и вполне удачный. В своих долгих поисках я случайно наткнулся на сайт белорусской компании AVS, торгующей звуковым оборудованием и нашел на нём интересный продукт – маленький сетевой стереопроигрыватель URRI MP A1 и сетевой ресивер URRI А1. Покупка и изучение этого устройства и заочное знакомство с его создателями привели в конце концов к определенным успехам: мной была создана библиотека скриптов для управления стереоресивером URRI из Роутер ОС Микротик. Но обо всем по порядку … Руководителем группы, создавшей собственный сетевой проигрыватель и ресивер URRI, является белорусский предприниматель Андрей Гапеев. Работа со звуковым оборудованием, создание и реализация проектов различных  аудио-видео решений, домашних кинозалов и мультирум привели его в 2018 г. к идее сделать собственный сетевой стереоресивер. В собранной им команде программистов и инженеров (Роман Плотников — инженер программист, менеджер проекта; Дмитрий Халява —  инженер программист, Linux разработчик; Игорь Ильин -  радиотехник;  Антон Нацвалов – программист разработчик приложения для Android; Андрей Ходько – радиотехник, звукорежиссёр; Дмитрий Гавриленко — звукорежиссёр; Сергей Преснаков – радиомеханик) в 2018 г. была начата работа над стереоресивером.  Название URRI было предложено супругой Андрея и выбрано в память известного советского кинофильма 1979 г. «Приключения Электроника» по имени одного из его героев – Урри, того самого, который пытался ответить на вопрос «где у него кнопка ?». Весь 2018 год велась работа над ПО и аппаратной частью устройства. Очень много работы было проделано со звуком. Авторы понимали, что бороться за Hi-END звук им не под силу, а максимально сохранить звук таким, каким его выдает процессор, можно постараться. Для разработки схемотехники авторы ресивера обратились на завод «Зенит» (завод выпускал магнитолу Беларусь). С Зенитом было сделано несколько прототипов URRI. В дальнейшем эта работа очень помогла, за что необходимо отдельно благодарить  главного конструктора завода  Алексея Чеха.  Опыт члена команды разработчиков URRI Игоря Ильина в DIY audio помог найти правильное решение со звуком. В середине 2019 года были заказаны первые версии материнских плат стереопроигрывателя и стереоресивера.  Платы были заказаны на двух предприятиях: на белорусском предприятии «Резонит» и в Китае.   Платы пришли быстро, по качеству вопросов не возникло. Далее была продолжена работа по звуку, в которой была большая заслуга  Андрея Ходько и Дмитрия Гавриленко - звукорежиссёров, с которыми ранее был уже реализован ряд совместных проектов. Эти работы привели к изменениям в схемотехнике устройств, что повлекло, естественно, к  заказу новой версии плат. На новых платах были отработаны этапы сборки проигрывателей и ресиверов, началось их малосерийное производство и применение в собственных звуковых проектах. В процессе эксплуатации на реальных объектах, где стереоресиверы должны были работать в режиме 12/7/365, были исправлены многие ошибки в ПО и расширен функционал устройства для режима контроля трансляции iSBC— (internet stream broadcast control).  В ходе работы, авторами была создана собственная большая база интернет радиостанций во избежание, в том числе, проблем блокировки различных Интернет радиоресурсов. При создании ПО авторы использовали кастомную сборку Linux на базе ядра 5.8.9. Отказ от использования звуковых серверов и использование одной лишь ALSA позволили добиться того звука, который и был заложен при мастеринге трека. Андрей рассказал мне в письме, что если отключить программный регулятор громкости или выставить его на максимум, и дальше регулировать уже только ручкой усилителя (присутствует только у ресивера), то можно говорить уже о звуке bit-perfect, что подтверждают на слух заядлые аудиофилы.  Отдельный сервис проверки целостности служебных файлов самостоятельно вытягивает систему из почти безнадежных случаев. Контроль получения обновлений и согласие пользователя на его установку позволили избежать проблем, которые могли возникнуть при пропадании интернета или питания во время скачивания обновления, а также при установке в неудобное пользователю время.  Устройства  с версией LITE предназначены покупателям, которые используют  устройство для простой задачи - прослушивание музыки и только. Версия PRO имеет расширенный функционал  и была сделана для инсталляторов, для того чтобы они могли зарабатывать на продаже устройства. Версии URRI A1 или URRI A1 PRO имеют разные прошивки - LITE и PRO и не могут участвовать в одном проекте.  Стерео ресивер способен выполнять следующие функции: Воспроизведение аудио-потоков (интернет-радио) из собственной базы или указанных/ добавленных пользователем Воспроизведение музыкальных файлов с USB-носителя Воспроизведение музыкальных файлов с сетевого хранилища или компьютера, находящихся в единой локальной сети Воспроизведение музыки с iTunes или iPhone / iPad / iPod touch через протокол AirPlay Мультирум, выступая в качестве как Slave так и Master устройств Использоваться в качестве стерео усилителя Интеграция в систему «Умный дом» Для организации системы фонового звука дома, магазина, бара, ресторана Цена устройства – версии lite 450 белорусских рублей (около 13 тысяч российских); версия Pro стоит на 100 белорусских рублей дороже:  550 рублей (немногим меньше 16 тысяч российских). URRI медиаплейер (самый первый продукт AVS) стоит 410 белорусских рублей и сейчас, насколько я понял, практически заменен производством URRI ресиверов. Основные характеристики аппаратной части ресивера URRI: процессор  ARM Cortex А7 v7hf 1200 МГц 4 ядра; DDR3 ОЗУ 512 Мб; NAND Flash 16 Гб; LAN Ethernet 10/100Мбит/с  встроенная в SoC; Wifi адаптер 802.11 b/g/n; DAC- Codek Soc; усилитель TPA3110D2 Texas Instruments; Мощность  2*30 Вт (4 Ом) / 2*15Вт (8 Ом) Коэффициент нелинейных искажений  0,006 Соотношение сигнал шум  102 Дб Диапазон воспроизводимых частот 20Гц-22 кГц Поддерживаемые форматы  ALAC, FLAC, AAC, ACC+, MP3, WAV, APE, OGG, OPUS Частота дискретизации аудио сигнала  8 - 192 кГц Цифровое подключение к внешнему DAC -  USB A, 1 разъем Аналоговый вход/выход   3,5 мм стерео Потребляемая мощность  40 Вт Потребляемая мощность в режиме ожидания  0,3 Вт Размеры (ШхВхГ)   116 х 50 х 130 мм Вес  450 гр. черный стильный алюминиевый корпус отдельный блок питания 18В-5А управление устройством – собственное приложение AVS Play (для Андроид), приложение Home Bridge для Windows, APPLE и IOS.   Как видно из аппаратных характеристик, малыш, по размерам, URRI обладает незаурядной «силой», имея весьма шустрый процессор и весьма неплохой объем оперативной и Flash-памяти. Внутри корпуса URRI представлен на удивление «полупустой» платой небольшого размера (так как практически всё интегрировано в Soc). Вторая (поменьше) - принадлежит Wifi-модулю (как я думал изначально, потом здесь мне подсказали, что это Orange Pi Zero с интегрированным Wifi-модулем) Подробное описание стереоресивера URRI представлено в руководстве пользователя (можно скачать здесь) и я, разумеется, не буду его повторять. Если кратко остановиться на достоинствах можно отметить малые размеры, хороший звук, наличие по сути двух сетевых карт для подключения к сети (LAN и WIFI), возможность присоединять как пассивные 4 и 8 ОМ-ные колонки (через евроблок), так и активные колонки (через джек АUDIO OUT). Возможность подключения внешнего аудио источника к AUX через джек AUDIO IN. Ресивер поддерживает работу со звуком по протоколам DNLA (можно использовать приложение Home Media Server для Windows), а также специальные приложения для телефонов и сетевых хранилищ, таких как, например, QNAP и SYNOLOGY и протокол AirPay (для Apple). Версия PRO оснащена возможностями расширенных сетевых настроек и системой контроля трансляции, позволяющей при отсутствии основного потока не допустить «тишину в эфире» и перейти скажем к вещанию с USB-носителя. Весьма удобным инструментом управления URRI является созданное приложение для Android - AVSPlay. Для программистов важным фактом является открыто распространяемый URRI API и тем самым возможность интеграции URRI по сути в любое программное обеспечение. Почитав описание, я решил приобрести стереоресивер для изучения. Покупке URRI немало способствовал найденный мной в руководстве пользователя раздел «Умный дом», в котором значилось дословно следующее: «Для интеграции стерео ресивера в систему «Умный дом» разработаны API, которые мы можем предоставить по запросу.  Пример API: Начать/продолжить воспроизведение POST запрос: http://[ip-adress:port]/play»  Конечно же такая возможность не могла не вызвать моего интереса и я сразу подумал о возможной интеграции URRI и Milrotik, посредством мощнейшего скриптового языка последнего, и в том числе универсальной команды /tool fetch, позволяющей организовать GET/POST запросы к хостам сети. Тем более, что опыт подобных работ у меня уже был при создании скриптовых библиотек для работы с различными PDU (таких как Netping, Laurent и Rodos). За обещанным API я обратился к разработчикам и Андрей переслал мне последнюю на то время версию API 2.7.5 для URRI A1 PRO.  С этого момента началась уже моя работа по созданию библиотеки скриптов управления стереоресивером URRI для роутеров Микротик, которая заняла около 2-х недель. Работая над созданием библиотеки функций, я проверил корректность работы каждой API команды URRI. В целом всё было хорошо, за исключением выявленных некоторых багов и ошибок, без чего не обходится, как правило, не один релиз. Например, я никак не мог подключить URRI к беспроводной сети своего роутера, в том числе попробовав поменять массу настроек wifi на роутере. Ларчик в конце концов открылся просто – оказывается прошивка URRI не позволяла соединиться с Wifi-сетью, SSID которой содержала в имени специальные символы. Как только я изменил имя своей Wifi-cети произошло соединение ресивера с беспроводной сетью и URRI получил IP-адрес … Все выявленные мной ошибки в работе API я передал разработчикам, которые обещали их исправить. Вероятно, я даже несколько утомил их своей дотошностью, но, тем не менее, Андрей Гапеев и Роман Плотников мужественно отвечали на все мои письма, содержащие ошибки и неточности в работе URRI. Я же в итоге написал библиотеку функций управления URRI, содержащую 60 команд-функций, не поддержав в первой версии своей библиотеки только режим контроля трансляции и настройки будильников URRI. Следует отметить, что в работе мной был использован  парсер  JSON-данных JParseFunctions (https://github.com/Winand/mikrotik-json-parser), прекрасно справляющийся с парсингом JSON ответов API в многомерные ассоциативные массивы РОС, за что огромное спасибо его автору. Все остальные возможности API URRI version 2.7.5 были поддержаны для управления из Роутер ОС.  Библиотека скриптов содержится в одном скриптовом файле (свободно доступна здесь). Для установки функций в репозиторий роутера следует выполнить команду:  /import file=URRI_v03022021_red2702.rsc                 На сегодняшний день актуальной версией является версия библиотеки от 03.02.2021 г. в редакции от 27.02.2021 г. При удачном импортировании скриптов в репозитории  роутера  пользователя  должны появиться  следующие  новые  скрипты,  созданные  вдадельцем  (owner) «URRI»:  Func_URRI_start - стартовый скрипт, устанавливает функции в окружение переменных  Func_URRI_part1 - соответствующие части библиотеки функций  Func_URRI_part2  Func_URRI_part3  Func_URRI_part_Special – специальные и служебные функции Func_URRI_call_examples – скрипт с примерами обращений к функциям библиотеки  Func_URRI_script_call_sheduller – пример сценария для Планировщика Роутер ОС  JParseFunctions – JSON –парсер для Микротик Роутер ОС  Для установки функций библиотеки в область Environment (т.е. активации) следует выполнить команду /system script run Func_URRI_start. Функции устанавливаются в окружение в качестве глобальных переменных. Для их использования в скриптах пользователя остаётся лишь их предварительно декларировать (:global FuncURRIfuncname, где funcname – имя конкретной функции). Для удобства все имена функций работы с URRI ресивером начинаются с префикса FuncURRI, за которым следует индивидуальное имя команды/функции и параметры.  Подробное описание работы с библиотекой скриптовых функций, в том числе нюансы работы с каждой функцией, описаны в руководстве по использованию библиотеки скриптов (можно скачать здесь). Все функции по API можно разделить на группы (функции воспроизведения, функции запроса параметров, специальные функции (расширенные сетевые настройки, подключения к Wifi и LAN, апгрейд прошивки, обновления базы радиостанций и т д…) Перечень всех функций библиотеки для управления ресивером из Микротик можно посмотреть в отдельном файле по ссылке выше. В качестве примеров кода я приведу примеры трех функций библиотеки:  Функция FuncURRIplay  # FuncURRIplay – главная функция воспроизведения # включает воспроизведение с ранее установленного источника или с пресета [1-4], а также c USB (первая папка) или AUX # если не указано - с ранее установленного источника  :global FuncURRIplay do={ :if ([:len $0]!=0) do={ :global URRIaddr; :global URRIport :if (([:len $URRIaddr]!=0) and ([:len $URRIport]!=0)) do={ :local StrFetchUrri; :local preset :if ([:len $1]=0) do={:set StrFetchUrri ("http://"."$URRIaddr".":"."$URRIport"."/play")} :if ($1="USB") do={:set StrFetchUrri ("http://"."$URRIaddr".":"."$URRIport"."/playFirstUsbFolder");}  :if ($1="AUX") do={:set StrFetchUrri ("http://"."$URRIaddr".":"."$URRIport"."/enableAUX")} :if (([:len $1]!=0) and ($1!="USB") and ($1!="AUX")) do={:set preset ($1-1); :set StrFetchUrri ("http://"."$URRIaddr".":"."$URRIport"."/preset/"."$preset"."/play")} :if (([:len $1]=0) or ($1="USB") or ($1="AUX") or ([:tonum $1]>0) and ([:tonum $1]<5)) do={ do { :global URRIanswer [/tool fetch url=$StrFetchUrri mode=http http-method=post as-value output=user]; } on-error={:return "ERROR FETCH function $0"} :global URRIanswer; :if (($URRIanswer->"status")!="finished") do={:return "ERROR"} #:return ($URRIanswer->"data"); :global FuncGetURRIanswer; :return [$FuncGetURRIanswer ($URRIanswer->"data")];      } else={:return "ERROR number preset mismatch"}    } else={:return "ERROR no define address or port"}  } } Функция FuncURRIvolume # - FuncURRIvolume – функция регулирования громкости # устанавливает громкость воспроизведения в % [0-100] # если $1 не указан, устанавливается громкость 30% # если параметр $2="smooth" используется алгоритм плавного регулирования громкости # в $3 можно задать «крутизну» (шаг) спада/нарастания громкости, если не указано по умолчанию установлен «5» :global FuncURRIvolume do={ :if ([:len $0]!=0) do={ :global URRIaddr; :global URRIport # объявим саму себя для рекурсивного вызова ! :global FuncURRIvolume :global FuncURRIgetVolume :local spad 5; # величина определяющая быстроту спада/подъема громкости при плавном регулировании :if (([:len $URRIaddr]!=0) and ([:len $URRIport]!=0)) do={ :local smooth ""; :if ([:len $2]!=0) do={:set $smooth $2} :local volume; :local setvolume [:tonum [$FuncURRIgetVolume]] :if ([:len $1]=0) do={:set volume 30} else={:set volume $1} :if ([:len $3]!=0) do={:set $spad $3} #:log warning $setvolume; #:log error $volume :if ($setvolume!=$volume) do={ # если разница между настроенной желаемой громкостью меньше спада, то настроить громкость за один раз :local st; :if ($setvolume>$volume) do={:set st ($setvolume-$volume)} else={:set st ($volume-$setvolume)} :if ($st<=$spad) do={:set $smooth "";}  # работаем здесь только при плавном регулировании, используется рекурсивный вызов самой функции :if ($smooth="smooth") do={ :while ($volume!=$setvolume) do={ :if ($volume>$setvolume) do={[$FuncURRIvolume ($setvolume+$spad)]; :set $setvolume ($setvolume+$spad); :if ($setvolume>$volume) do={[$FuncURRIvolume $volume]; :set $volume $setvolume;}} :if ($volume<$setvolume) do={[$FuncURRIvolume ($setvolume-$spad)]; :set $setvolume ($setvolume-$spad);  :if ($setvolume<$volume) do={[$FuncURRIvolume $volume]; :set $volume $setvolume;}}      }    } else={ # работаем только при установке громкости сразу :local StrFetchUrri; :set StrFetchUrri ("http://"."$URRIaddr".":"."$URRIport"."/setVolume/"."$volume");  do { global URRIanswer [/tool fetch url=$StrFetchUrri mode=http http-method=post as-value output=user]; } on-error={:return "ERROR FETCH function $0"} :global URRIanswer;  :if (($URRIanswer->"status")!="finished") do={:return "ERROR"} #:return ($URRIanswer->"data"); :global FuncGetURRIanswer; :return [$FuncGetURRIanswer ($URRIanswer->"data")];           }        } else={:return $volume}    } else={:return "ERROR no define address or port"}  } } Вышеприведённый код функции FuncURRIvolume интересен тем, что в ней используется рекурсивный вызов «самой себя» для плавного регулирования громкости – поэтапного повышения или понижения (см. код и комментарии к нему).  Функция FuncURRIsettings предназначена для считывания параметров состояние ресивера (для части параметров необходимо также пользоваться функцией FuncURRIstatus). # - FuncURRIsettings # получить состояние устройства :global FuncURRIsettings do={ :if ([:len $0]!=0) do={ :global URRIaddr; :global URRIport :if (([:len $URRIaddr]!=0) and ([:len $URRIport]!=0)) do={ :local StrFetchUrri ("http://"."$URRIaddr".":"."$URRIport"."/getSettings");  do { global URRIanswer [/tool fetch url=$StrFetchUrri mode=http http-method=post as-value output=user]; } on-error={:return "ERROR FETCH function $0"} :global URRIanswer; :if (($URRIanswer->"status")!="finished") do={:return "ERROR"} /system script run JParseFunctions; global JSONLoads; :set URRIanswer [$JSONLoads ($URRIanswer->"data")] :if ([:len $1]=0) do={:return $URRIanswer;} else={ :if ($1="version") do={:set URRIanswer ($URRIanswer->"deviceInfo"->"version")} :if ($1="cpuTemp") do={:set URRIanswer ($URRIanswer->"deviceInfo"->"cpuTemp"); :local cpuTemp $URRIanswer; :local Temp ""; :for i from=0 to=([:len $cpuTemp]-1) do={:if ([:typeof [:tonum [:pick $cpuTemp $i ($i+1)]]]="num") do={:set $Temp ("$Temp"."$[:pick $cpuTemp $i ($i+1)]")}} :return $Temp} :if ($1="LAN") do={:set URRIanswer ($URRIanswer->"networkSettings"->"connections"->"LAN")} :if ($1="WLAN") do={:set URRIanswer ($URRIanswer->"networkSettings"->"connections"->"WLAN")} :if ($1="autoPlay") do={:set URRIanswer ($URRIanswer->"audioSettings"->"autoPlay"->"value")} :if ($1="autoUpgrade") do={:set URRIanswer ($URRIanswer->"deviceInfo"->"autoUpgrade")} :return $URRIanswer;}    } else={:return "ERROR no define address or port"}  } }  Функция выше наглядно демонстрирует мощные возможности JSON-парсера для Микротик, позволяющего без всяких проблем перевести ответ API прошивки из JSON в многомерный ассоциативный массив и потом уже работать с ним, извлекая все или какой-либо один требуемый параметр настроек URRI.  Отмечу, что по сравнению с возможностями API, мной, для изюминки, были реализованы некоторые дополнительные возможности работы с URRI. В качестве примера можно привести вышеприведенную функцию установки громкости с плавным програмным регулированием (постепенным нарастанием или спадом) FuncURRIvolume или функцию FuncURRIScope, позволяющeй провести сканирование по пресетам, USB- и входу AUX с поочередным воспроизведением из этих источников в течение заданного времени и количества «кругов» воспроизведения.  Также в модуль скрипов были добавлены служебные функции, содержащиеся в части «Speсial» и необходимые для составления сценариев воспроизведения и работы многих основных функций библиотеки. Используя функции библиотеки скриптов для URRI и Планировщика Микротик РОС можно спланировать график «вещания» с URRI по зарание составленному сценарию, а также реализовать «озвучивание» различных важных событий на роутере. В качестве примера приведу небольшой скрипт-сценарий для воспроизведения с URRI-ресивера, который можно поместить в CRON (Планировщик, Scheduler) роутера Микротик. В скрипте задействована специальная служебная функция [$FuncSchedFuncAdd], которая может планировать задания планировщика в заданную дату и время или «на лету»:   # пример скрипта, сценария, добавляющего задания в планировщик роутера для URRI  # объявляем функцию добавления функций в планировщик :global FuncSchedFuncAdd  # добавить проигрывание пресета 2 в указанную дату и время   # добавить плавное регулирование громкости   # добавить воспроизведение USB    # добавить остановку воспроизведения   # добавить включение обзорного проигрывания с пресетов и USB в один круг :delay 10s;   # добавить включение радиопотока радио Брест: :delay 120s;    Каждая функция библиотеки «завернута» в обработку ошибок, которая не позволяет остановить исполнение скриптов при возникновении внештатных ситуаций. При различных типах ошибок (неправильно заданных параметрах функций, отсутствие доступности ресивера в сети и т д…) соответствующее сообщение об ошибке будет возвращено вызывающему скрипту.  Теперь мой Микротик обладает не только винтовкой-трехлинейкой (динамиком-пищалкой), способной воспроизводить простые однотональные мелодии командой :beep. «Вооруженный» дополнительным пулемётом в сети (стереоресивером URRI), Микротик, с помощью библиотеки скриптов может озвучивать любые события, происходящие в сети (например, подключения/отключения wifi-пользователей, vpn-пользователей, попытки несанкционированных входа на роутер, сообщения о критических ошибках и т д…) Для этого необходимо лишь записать соответствующие «джинглы» (в том числе смыслоголосовые), разместить их на USB-носителе и вызывать воспроизведение с соответствующих папок USB по мере необходимости. Это очень удобно, скажем, если URRI и стереоколонки аудио системы расположены непосредственно в кабинете администратора сети. Используя несколько URRI, объединенных в систему мультирум, и роутер Микротик можно совсем не дорого реализовать систему офисного оповещения об экстренных ситуациях, собраниях, событиях на работе и т д... Также можно организовать воспроизведение музыки и специальных голосовых сообщений на удаленных объектах, на которых, например, сторож, как таковой отсутствует, но есть видеонаблюдение. При видеофиксации проникновения на объект современная видеокамера может не только самостоятельно оповестить удаленную охрану, но и подать «сигнал» в сеть, например в виде передачи фото объекта, а значит появления трафика от определенного IP через определенный порт.  Далее роутер микротик, приняв тревожный сигнал, управляя воспроизведением на URRI-ресивере может отпугнуть воров, сообщив им в соответствующей форме, что мы про них думаем и что их скоро сцапают стражи правопорядка  …        Надо сказать, что авторы проекта не стоят на месте постоянно совершенствуют свой продукт (URRI-ресивер), обновляют прошивку и дополняют базу радиостанций. В планах разработчиков сделать смарт-радио и интерьерную смарт-картину для конечного пользователя - аналогичные URRI хабы для «Умного дома». В данное время коллектив разработчиков URRI занимается подключением системы Noolite к URRI-ресиверу для взаимодействия с беспроводными датчиками и выключателями и фактически уже реализовал данный функционал, о чём свидетельствует появление соответствующей новой кнопки в AVSplay приложении.       Желаю дальнейших успехов авторскому коллективу разработчиков URRI и благодарю отдельно Андрея Гапеева и Романа Плотникова за предоставленный  API и пояснения в работе прошивки URRI в ходе создании скриптовой библиотеки функций для роутеров Микротик, а также предоставленные материалы об истории создания ресивера. Серков Сергей Владимирович (Sertik), 27.10.2021 г. пишу скрипты для роутеров Микротик