VRack2 — Кот аристократ в мире локальной автоматизации
- суббота, 14 марта 2026 г. в 00:00:05
Это большая статья про дешевую локальную автоматизацию на основе VRack2. Будет очень много тем разной направленности. Работа с железом, мелкие сервисы, организация инфраструктуры.
По сути это компиляция моей работы за последние несколько лет. Важно подметить - моей и только моей.
Если какая-то тема не привлекает - просто переходите к следующей, скорее всего на что-нибудь интересное наткнетесь.
Вначале я приведу немного вводной информации, потом будут практические реализации.
У вас появилась задача локальной автоматизации. На самом деле не особо важно что вы конкретно хотите сделать - маленький сервис для бекапа или автоматизацию своего большого пивного заводика - скорее всего вы столкнетесь с одними и теми же проблемами:
Удаленное управление
Включение/выключение/автоматический перезапуск
Проблема отслеживания сервиса
Падения
Онлайн мониторинг работы
Алертинг/ивентинг
Проблема онлайн взаимодействия (например, ручной запуск бекапа)
Систематизация подобных сервисов
Где что должно лежать и как запускаться
Взаимодействие между сервисами
И таких пунктов во время реализации значительно так прибавится.
А еще у нас считается, что автоматизация бывает разная. Бекапы это одно, а вот промышленная автоматизация это другое.
Решение, про которое я сегодня вам расскажу, позволяет делать все вместе и сразу, а самое главное очень дешево. Поэтому неважно, кто вы - системный администратор или инженер автоматизатор. Это решение может быть для вас.
VRack2 (OpenSource) работает в среде NodeJS и использует язык JavaScript/TypeScript. Могу понять ваше разочарование - JS/TS не каждому охота будет увидеть в качестве языка для автоматизации. Тогда почему JS? Все очень просто - JS очень ДЕШЕВЫЙ.
Если разобраться, что такое автоматизация - это реакция на событие и выполнение работы. Улавливаете намек? Поскольку JS событийно-ориентированный язык - он идеально подходит для локальной автоматизации.
Эти прелести дополняет огромнейшея стандартная библиотека. Иногда получается писать крупные сервисы абсолютно без внешних зависимостей, позже я расскажу про один такой. Встроенные инструменты организованы просто и их легко начать использовать.
Знаете классический выбор - мучаться, страдать и знать или просто выполнять работу. Так вот на JS можно просто выполнять работу.
У JS очень маленький порог входа. Если не использовать TS, то как язык он очень простой и не имеет строгой типизации. Очень много делается за программиста, позволяя ему сосредоточиться на решении конкретной задачи.
JS очень хорошо подходит для автоматизации из-за своего внутреннего устройства. Просто посмотрите как легко подписаться на изменения внутри директории:
require('fs').watch('/path/to/folder1', (eventType, filename) => { // Срабатывает при изменениях в folder1 console.log(eventType, filename); // Выводит тип события и имя файла }); require('fs').watch('/path/to/folder2', (eventType, filename) => { // Срабатывает при изменениях в folder2 console.log(eventType, filename); });
И вам не важно что происходит в других местах, вы просто определяете реакцию на событие. Люди, которые не знакомы с асинхронным кодом, могут не совсем понять что происходит. А вся магия в том, что в JS практически все происходит по событиям. Ваше приложение может ожидать входящего HTTP сообщения, выполнять задачи в системе, отправлять системые уведомления и все это делать по событиям не блокируя друг друга.
К такому программированию нужно привыкать. Вы даже можете не знать, где на данный момент находится ваш интерпритатор и что он выполняет, для вас важно, чтобы выполнилось то, что должно выполниться при определенных событиях.
Еще одна особенность JS - он не виснет как тварь со странными ошибками. Недавно мне потребовалось быстро организивать TCP->RS232 тунель. Для этих целей использовал софт на python. Каково же было мое разочарование, когда после того, как я вытащил преобразователь usb-com, у меня это приложение повисло намертво. Флешбеки ударили мне в голову и я сразу вспомнил кучу других Windows приложений, которые намертво подвешивали интерфейс программы при работе с COM портом.
В JS же все происходит просто. Когда человек вытаскивает usb->com преобразователь - происходит событие, которое можно корректно отработать. И все - все просто.
Это касается и других вещей, например прямого управления сокетами. Мне приходилось писать на чистых сокетах на PHP или Си, да и java не особо далеко ушла. Скажу честно - удовольствие не из приятных.
В JS все так и работает - вместо того, чтобы пытаться сделать все линейно, вы просто подписываете обработчики на события и систематизируете код уже внутри них.
Как это обычно бывает (псевдокод):
const sock = new Socket() sock.on('data', (data: Buffer) => { // обрабатываем данные, приходящие с сокета }) sock.on('error', (err: Error)=>{ // Обрабатываем ошибки }) sock.on('close', ()=>{ // Обрабатываем разрыв соединения })
Надо сказать, что асинхронность накладывает определенные архитектурные особенности. Например, если вы раньше могли писать такой код:
socket.write(request) a = socket.read(1000)
То в асинхронном коде такие простые вещи делаются наоборот - немного сложнее. Поскольку у нас есть независимые методы, которые запускаются внешними факторами, нам приходится немного менять свои подходы.
К примеру, если нам нужно реализовать тот же принцип (отправка пакета и ожидание 1000мс), нам нужно пойти другим путем.
/** * Метод, который мы вызываем вместо: * * socket.write(request) * a = socket.read(1000) * * будет вызываться так: * * a = await requestPromise(request, 1000) */ requestPromise(request, timeout){ // resolve & reject это функции, которые можно вызвать, чтобы закончить асинхронный метод // Пока они не будут вызванны - метод не будет выполнен! // То есть метод ничего не вернет и будет ждать вызова resolve | reject // resolve(data) - для успешного завершения метода // reject(new Error()) - для вызова ошибки return new Promise((resolve, reject)=>{ // Сохраняем - это важно this.resolve = resolve // создаем таймаут - если таймаут вышел - вызываем reject для завершения с ошибкой this.timeoutTimer = setTimeout(() => { reject(new Error('Request timeout')); this.resolve = false this.timeoutTimer = false }, timeout); // Теперь записываем данные в socket this.socket.write(request) }) } /** * Метод, который вызывается, когда socket получает данные. * До этого при подключении вы уже забиндили этот метод типа так: * * this.socket.on('data', this.socketOnData.bind(this)) * */ socketOnData(data){ // Если нам пришли данные и у нас есть активный resolve - вызываем его с данными // В конечном итоге data вернется как результат выполнения метода // a = await requestPromise(request, 1000) // и a будет равна data if (this.resolve) this.resolve(data) // Сбрасываем наш таймаут ошибки, мы же данные то получили if (this.timeoutTimer) clearTimeout(this.timeoutTimer) }
Возникает вопрос, а почему так сложно - раньше же все просто было? А тут есть концептуальное отличие - функции write и read(1000) выполнялись синхронно, а await requestPromise() асинхронно. Это значит, что интерпретатор после отправки this.socket.write(request) мог заниматься другими важными делами. То есть код приложения мог работать дальше без проблем, когда в конкретном месте вы ожидали выполнение запроса a = await requestPromise(request, 1000).
Говоря проще, если запустить такой код:
// Запускам любой асинхронный код setInterval(()=>{ console.log('tick tack') }, 100) console.log('start request') // Запускаем наш запрос a = await requestPromise(request, 1000) console.log('end request')
Вот что мы увидим в консоли:
``` start request tick tack tick tack ... в сумме ~10 тиков Error: Request timeout... ```
И после таких примеров вам может показаться, что ну его - коту под хвост. Но опять же не торопитесь с выводами. Дело в том, что обернуть soсket для того, чтобы он работал как синхронный, не сложно, хоть и может по-началу вызвать вопросы. Другое дело, когда вам нужно код, например Си, обернуть как полноценно асинхронный - тут уже дело далеко не 5 минут.
Действительно, те вещи, которые в других языках можно было бы сделать двумя строчками, в JS могут делаться не двумя строчками, но зато вы получаете на самом деле куда больше контроля и куда больше возможностей.
Я согласен с тем, что JS сам по себе как язык просто УЖАСЕН. Да это так. НО не торопитесь его закапывать, серьезно, сейчас все решим.
У JS есть некоторые особенности в отношении типов/объектов. Например, тип null это объект. Если не знать особенности, можно удивиться от поведения интерпретатора. Но, во-первых, эти вопросы обычно быстро решаются, а во-вторых, можно использовать TS, который даже линтером подсвечивает практически все странные и мутные места.
Многие считают, что в TS нет смысла, ведь он все равно компилируется в JS. Все же TS позволяет исключить множество ошибок еще на этапе компиляции, а так же стандартизировать некоторые интерфейсы, это может быть удобным. Еще вы можете компилировать свой проект под разные стандарты JS, что позволит вам запускать один и тот же код на очень разных версиях NodeJS.
У использования чистого JS есть хорошая сторона - очень быстрое прототипирование. Некоторые проекты просто увязают в типах и архитектурных паттернах, не дойдя до чего-то интересного. В JS же все куда проще, часто он позволяет делать то, что в других языках просто недопустимо.
Вопрос типизации закрываем. Хотите типы - есть TS, хотите быстрое прототипирование - берите JS.
Вторая проблема, с которой сталкиваются люди - это организация событийно-ориентированного кода. Эту проблему решает уже мой проект - VRack2-Core - фреймворк для создания событийно-ориентированных сервисов.
Если вы пробовали писать на NodeJS сервисы, то вы уже должны были столкнуться с тем, что событийно-ориентированный код очень сложно структурировать. Это чем-то похоже на мир, когда еще не было MVC и каждый писал код как ему было удобно.
Раньше, когда NodeJS только начала набирать популярность - весь код выглядел как куча вложенных CallBack функций, что, в конечнои итоге, прозвали CallBack Hall.
Время шло, подходы менялись, но внятного решения, видно не было.
VRack2-Core - это как MVC, только для мира событийно-ориентированного кода. Он определяет правила организации кода, структуру файлов и предоставляет базовые компоненты для их реализации.
Сервис, написанный на VRack2-Core, строится на трёх основных элементах:
Структура сервиса - определяет список компонентов и их взаимодействие.
Компоненты (устройства) - содержат исполняемую логику.
Библиотеки (опционально) - вспомогательные модули.
Описывается в сервис-файле, где перечислены компоненты, настройки и связи (я сам ненавижу подобное, эти конфиги... json, yaml. Поэтому, этот момент сделан максимально просто и интуитивно, не стоит ссаться раньше времени).
Резонный вопрос - а на кой черт это все надо? можно же просто код писать. Все не так просто, к сожалению. Когда наш код выполняется линейно, у нас не возникает вопросов, что и когда выполнится.
Если брать событийно-ориентированный код, то там все происходит по событиям. Когда и что происходит сходу разобрать не выйдет. В рамках одного события все просто, но как позволить другим компонентам системы подписываться на это событие?
Приведу пример:
Представим ситуацию, когда нам нужно получать события Asterisk и что-то с ними делать, возьмем все абстрактно:
import AsteriskApi from 'asterisk-api' // ... Настройки подключения и тп... Asterisk.on('call', (callInfo)=>{ // А тут нам что делать? // Ну, допустим, у нас есть класс CallManager CallManager.call(callInfo) })
Казалось бы, вроде все хорошо. Но что если, к примеру, при звонке с определенного номера должны еще открываться двери? а еще нам бы хотелось как-то отслеживать сообщения callInfo.
И вот уже наш код превращается в "это":
import Asterisk from 'asterisk-api' ... Asterisk.on('call', (callInfo)=>{ CallManager.call(callInfo) ParkingManager.verify(callInfo) EventManager.terminal(callInfo) })
Почему этот код ужасен? Класс, вместо того, чтобы предоставить стандартизированный интерфейс для передачи событий - сам занимается передачей этих событий.
Мы теряем мобильность, которую предоставляет нам событийно-ориентированный стиль программирования.
Хватит это терпеть! переходим на сервис-файлы.
Приведу наглядный пример схемы, построенной на основе сервис-файла из VRack2:

Важное отступление!
Кто-то из вас может уже подумать, что это очередная поделка для умного дома, или nocode платформа типа n8n. Или визуальный язык программирования. Не спешите с выводами!
Так уже гораздо лучше. Видно что есть некие компоненты, у них слева обработчики событий, а справа вызовы обработчиков. Мы можем подписываться на события и определять собственные обработчики событий для каждого компонента, а с помощью сервис-файла определять, кто и что будет вызывать.
Связи работают очень просто. Когда в ToggleSwitch происходит вызов выхода this.ports.output['state'].push(data) в SmartBulb происходит вызов обработчика входящего порта power - inputPower(data). То есть связи просто прозрачно позволяют вызывать обработчики других устройств.
Приведу очевидные плюсы сервис-файла:
Общая схема сервиса
Изменения поведение сервиса без изменения исходного кода компонентов
Например, мы можем добавить несколько умных лампочек и подписать их только на 2 управляющих компонента, и тогда они будут работать группой.
Проще вспомнить, что делает сервис, без изучения исходного кода
Проще искать точки входа для нового функционала
Может показаться, что сервис-файл будет вас сильно ограничивать. Скорее, он будет вынуждать вас более правильно архитектурно выстраивать. Компоненты могут и напрямую обращаться к друг другу, но этого не стоит делать в 99% случаев.
Это работяги, которые выполняют основную работу. Если, например, во flow системах типа NodeRed используются "ноды" для взаимодействия, то в VRack2 работу выполняют устройства и ничего общего у них с нодами нет.
Почему именно «устройства», а не «компоненты» или что-то ещё? Потому что, когда мы проектируем их как устройства, мы думаем о них так, будто они могут существовать в реальности. Даже если они абстрактные или полностью виртуальные, им приписывается логика настоящих устройств. Такое отношение - как к автономным и осязаемым объектам - делает их взаимодействие интуитивным и последовательным.
Внутри - это просто экземпляры классов, которые живут сами по себе и общаются только посредством связей.
Это абсолютно иной подход к разработке, в отличии от нод или визуального программирования.
Ноды обычно похожи на конечный автомат - пришло->выполнилось->ушло. А визуальное программирование старается разбить все на мелкие части.
Как уже выше писалось, устройства разрабатываются так, как будто бы они существуют в реально мире. Как из примера выше, у нас есть ToggleSwitch - это кнопка, Dimmer - управление уровнем света, и SmartBulb - умная лампочка. Несмотря на то, что это виртуальные устройства, если посмотреть на схему, они нам, людям абсолютно понятны, как и их взаимодействия.
Устройства могут быть и не виртуальными. Кнопка может быть реальная как и диммер, а лапочка виртуальная. Или наоборот, лампочка у нас может быть реальной и управлятся, к примеру, по API через wifi, а кнопки и диммер витруальные.
Приведу еще один интересный пример. Есть такой старый язык программирования - LD - для программирования релейной логики. В ней задаются простые правила, типа [ X1 ]----[ X2 ]----( Y1 ) = если входы X1 И X2 активны - включить выход Y1. Обычно он используется в ПЛК. Мы можем сделать подобие своего программируемого реле, используя, например, модуль DI+DO и VRack2. Напишем устройство, которое будет парсить код LD и применять логику к собственным портам, пусть оно выглядит как-то так:

Понятно, что входы будут отвечать за логические X1/X2/Xn, а выходы за Y1/Y2/Yn. Теперь мы можем его соединить с реальным модулем ввода-вывода, как-то так:

Забавно, что в VRack так получается, что у модулей ввода-вывода входы и выходы перевернуты. Например DI - дискретный вход - в VRack устройстве будет выходом, поскольку мы как бы должны отдавать статус дискретного входа. А DO - дискретный выход - будет у нас входом, поскольку должен принимать новое значение дискретного выхода.
Этот пример наглядно показывает, что в VRack нет границ между реальными и виртуальными устройствами. Часто они могут быть заменяемые для целей тестирования, оптимизации, обучения.
У такого подхода просто высочайшая мобильность. Вы можете взять любые железки и комбинировать их, а можете вообще собрать все виртуальным для целей обучения или тестирования. Создавать отличные абстракции над реальными устройствами, наглядно, дешево и практично управлять ими.
В некоторых проектах приходится использовать и витруальные, и реальные устройства.
К примеру - возьмем управление шлагбаумом. У него один вход - пропустить. Но "нажимать" его могут разные источники. Например, при распознавании номера, или физическая кнопка оператора, или веб интерфейс. И в каждом случае, смотря на схему, построенную на основе сервис-файла, мы видим эти источники и они нам понятны.
На самом деле мы все можем превратить в устройства. Что делать, если аналогов нет в реальной жизни? Придумывать! Возьмем Asterisk, из примера выше, сделаем из него устройство AsteriskApi:

Через вход можно управлять звонками, а с выхода любой желающий может получить информацию о событиях.
Устройства обычно общаются, используя только порты (хотя у них есть прямой доступ друг к другу в случае острой необходимости). Сейчас немного разберемся с их особенностями.
Устройства могут иметь разное количество портов, в зависимости от переданных настроек. То есть одно и то же устройство может выглядеть совсем по-разному:
vrack2-basic.Mixer с одними параметрами:

Тот же Mixer, но с другими параметрами:

Это позволяет динамически наращивать функционал устройства, делая их более универсальными.
Еще в VRack2 есть 2 типа портов - стандартные и возвращаемые.
Стандартные порты просто пробрасывают по связи любое значение. Возвращаемые же порты - как не сложно догадаться - возвращают значение.
Возвращаемые порты позволяют организовывать API подобное взаимодействие.
Давайте возьмем простой пример использования возвращаемых портов:

HTTPServer принимает HTTP запрос, формирует данные и передает их на свой выход, а полученный результат возвращает инициатору запроса. На самом деле это очень простой пример, обычно такие запросы проходят через несколько устройств, каждый из которых занимается своим делом, например шифрованием, или авторизацией, или роутингом. Но важно понимать, что для HTTPServer это все скрыто, он лишь вызывает событие и ждет результат, а что там ему вернется это уже не его дело.
Внутри HTTPServer это устроено как то так:
// ... получение http запроса и все такое // Формируем данные const data = { queryParams, body, url } // Отправляем на выход и ждем результат const result = await this.ports.output['memory.request'].push(data) // Отправляем результат пользователю http.response(result)
Внутри VRack2, кстати, приходящие через WebSocket Server запросы обрабатываются похожим образом:

Пунктирными линиями выделены связи, по которым проходит запрос пользователя API.
WSProvider принимает запрос, используя Websocket сервер, и передает его в ProvidersClients.
ProvidersClients - дополняет запрос информацией о клиенте и отправляет его в Guard.
Guard проверяет уровень доступа, расшифровывает сообщение и передает его в Master.
Master выполняет команду.
Когда команда была выполнена - результат возвращается обратно по цепочке прямиком клиенту WebSocket сервера. На кажом этапе результат может модифицироваться, например, удалением мета-данных или шифрованием результата.
У устройств есть много дополнительного функционала:
Дисплей (shares данные)
Индивидуальное хранилище
Органы управления (actions)
Метрики
Индивидуальные настройки, получаемые из сервис-файла
Сервисные сообщения
Устройства внутри - это классы. А значит, они поддерживают все приятные организационные особенности классов типа наследования и тп. Еще устройства могут вобще не использовать порты.
Начать писать свое устройство очень просто, минимальный код будет такой:
const { Device } = require ("vrack2-core") class MyDevice extends Device {} module.exports = MyDevice;
Не хочется пока заострять внимание на технической части. Чуть позже будет пояснение к базовому функционалу.
Устройства организуются в директориях вендора и имеют свои собственные зависимости:
devices/ my-vendor/ node_modules .git MyDevice1 MyDevice2 package.json vrack2-net/ node_modules .git Device1 Device2 package.json
То есть, все уже продумано так, что вы просто подтягиваете устройства с готовых репозиториев и запускаете сервис, предварительно установив необходимые каждому набору зависимости. Это очень удобно, потому что дает хороший контроль над node_modules
Устройства могут использовать любые npm зависимости без каких-либо ограничений.
Да, используя VRack2-Core, вы можете написать сервис в событийно-ориентированном стиле, и этот сервис даже будет работать. Но работать с этим сервисом будет немного неудобно. Сложно будет оперативно отслеживать его состояние, события и тп.
Чтобы предоставить полноценный сервис для разработки собственных сервисов - был написан VRack2.
Если VRack2 написан на VRack2-Core - значит он тоже имеет сервис-файл, можно посмотреть его схему и он состоит из устройств. Скажу больше, вы можете использовать устройства самого VRack2 внутри своих сервисов, запущенных в VRack2. Или вы можете расширять возможности VRack2, используя свои устройства.
Такие архитектурные решения дались непросто. Пришлось потратить несколько месяцев, просто пытаясь разделить коней от людей. Вторая версия VRack это, в первую очередь, огромная работа над формализацией и разделением сущностей.
Какие-нибудь n8n или NodeRed - это приложения, сделанные в одном архитектурном стиле, а автоматизация, разработанная в этих приложениях, сделана в абсолютно другом стиле. То есть вам сложно будет написать n8n на n8n, или NodeRed на NodeRed. Что сразу показывает свою ограниченность и узкую направленность.
Сам VRack2 и автоматизация, которая работает в нем, - все сделано в одном стиле, в одной модели и может использовать даже одни компоненты. Можно ли написать VRack2 на VRack2? легко. А это значит, что, устанавливая его, вы уже получаете полноценный сервис, работающий на нем же самом. Скорее всего можно попробовать запустить VRack2 внутри VRack2, но с небольшими конфигурационными доработками.
На самом деле, когда VRack2 запускает сервис внутри себя через воркер, он запускает еще один сервис, написанный также на основе VRack2-Core, который, в свою очередь, запускает уже ваш сервис, но предварительно подписывается на нужные события, предоставляя интерфейс для самого VRack2.
То есть вы не просто можете расширять своими устройствами VRack2, но и также расширять сервис, который запускает ваш сервис, чтобы предоставить дополнительное API, или, например, поменять стандартное поведение. Таким образом, можно, к примеру, вместо использования VRack-DB, использовать Clickhouse прозрачно для всех устройств внутри сервиса.
Девиз VRack2 - "Все ради сервиса" - не просто так. Он действительно разрабатывался так, чтобы предоставить максимум для сервиса.
В первую очередь это сервер. У него нет встроенного интерфейса, как у NodeRed. Но вы можете поставить VRack2-Manager для взаимодействия. Не ждите, что он даст вам накидать из готовых блоков сервис, интерфейс намеренно ограничен только определенным функционалом.
Не все сервисы должны работать 24/7, некоторые из них могут запускаться на пару дней или при необходимости. Если вы работаете с реальным железом, то бывает нужно отключать сервис для внесения изменений настроек через специализированное ПО. Поэтому предусмотрен функционал для ручного и автоматического управления сервисом.

В разделе управления сервисом есть интуитивно понятные кнопки, кроме одной - синей. Это кнопка проверки сервис-файла на наличие ошибок. Чтобы проверить корректность связей идентификаторов и тп без запуска самого сервиса.
В разделе ошибок мы можем посмотреть, что привело к краху сервиса. Ошибкам уделена значительная часть времени.
Пример ошибки при запуске сервиса:

Ошибки могут содержать другие ошибки и дополнительные описанные свойства. Например, тут видно, что есть дополнительная информация о настройке устройства, которое система пыталась инициализировать. Вложенная ошибка говорит, что конкретно случилось - Не нашелся обработчик для входящего порта. Дополнительной информацией указан входящий порт и название обработчика, который он ожидает увидеть внутри класса.
Если сервис упал с ошибкой CTR_ERROR_INIT_DEVICE - система не станет его перезапускать. Если сервис завершается определенными исключениями, система будет игнорировать автоматический перезапуск. Если же сервис упадет с ошибкой не из списка, то система попытается его перезапустить (если такое поведение разрешено). При входе в VRack2 Manager слева можно сразу увидеть красную иконку в списке сервисов, если в нем зарегистрированы ошибки.
Внутри VRack2 все также работает по событиям, и когда сервис падает, происходит внутренее событие, на которое вы можете подписаться и реагировать. Поэтому, при желании, можно настроить на продакшене отправку таких падений сразу в телеграм.
По каждому запущенному сервису мы можем получить только общие настройки мета-данных. Нельзя получить удаленно содержимое сервис-файла. Это может сильно навредить в случае если злоумышленник получит доступ к интерфейсу, потому что в сервис-файле могут храниться пароли или ключи. Это еще одно концептуальное сильное отличие от других noCode lowCode платформ. (Если что, в VRack2 есть ключи доступа и шифрование, но все равно так)
Все сервисы, запущенные внутри VRack2, являются отдельными воркерами, по которым собирается статистика - например, по потреблению памяти. Удобно, чтобы оценить - течет или нет.
Можно отобразить структуру сервиса (схему), например, для термостата:

А как ее исправить? А в этом плане VRack2 тоже очень сильно отличается от сервисов типа NodeRed. Если сказать просто - через интерфейс API - никак. Используя API практически никак нельзя навредить сервису внутри VRack2.
Если выбрать любое устройство, можно получить по нему документацию и текущую упрощенную схему подключения:

Когда вы разрабатываете устройства - вы автоматически их документируете. Вам не надо писать в документации что делают порты или опции. Все происходит на этапе написания кода - добавили порт - сразу же сформировалась документация на него.
На самом деле, получать документацию уже на запущенном устройстве не особо полезно, ведь мы его уже запустили. Мы можем получить документацию по каждому устройству, зарегистрированному в системе, через "Менеджер устройств". Он доступен даже без запущенных сервисов. Раздел "Менеджер устройств" доступен в VRack2 Manager и находится выше списка сервисов.
Далее, что нас интересует, это "События & Данные". Там доступ к системе бродкастов для получение данных в онлайн режиме.
Это очень важный функционал, который очень широко применяется. Например, для получения дисплея устройства:

Подписка на канал render обеспечивает автоматическую онлайн-доставку данных дисплея.
В классе устройства есть свойство shares - обычный объект, содержимое можно менять как угодно. После внесения любых изменений в shares и вызова метода this.render(), эти данные попадают в очередь и далее рассылаются бродкастом по каналу render, привязанному к данному устройству.
Таким образом, канал render позволяет в онлайн-режиме получать актуальные значения переменной shares. Вы можете вызывать this.render() сколько угодно - частота отправки данных ограничена 200 мс. Этого вполне достаточно для числовых и текстовых значений. При необходимости это ограничение можно уменьшить.
Внутри VRack2 есть система бродкастов. Когда вы нажимаете render - VRack2 Manager через WebSocket отправляет команду на подключение к бродкаст каналу. В данном случае строка канала будет такой services.bme-test.devices.BME1.render где bme-test идентификатор сервиса, BME1 идентификатор устройства, а render название канала.
У устройств есть и другие каналы, которые работают проще, чем канал render - terminal, notify, event, action, alert, error.
Сообщения на этих каналах отправляются моментально, без всяких задержек. Чтобы отправить сообщение, нужно просто вызвать внутри устройства this.terminal('string', any), this.notify('string', any)... Вы сами решаете как использовать такие сообщения. К примеру, я стараюсь сообщения типа alert всегда отправлять в мессенджер, а terminal использую как дебаг информацию.
Получение таких сообщений в интерфейсе выглядит как-то так:

Если вы не поняли, как полноценно можно это все использовать - не беда, чуть позже я все расскажу.
VRack изначально разрабатывался так, чтобы он мог работать на всяких raspberry pi и тп. У него по умолчанию есть только 2 инструмента, которые вносят изменения на диск - сохранение структуры сервиса и локальное индивидуальное хранилище внутри устройства.
То есть, в VRack2 по умолчанию нет никакой системы логирования. Обычно вы просто отсылаете нужные вам события в нужные места, без сохранения их на диск. Это может быть мессенджер или ваша большая система логирования, работающая уже на полноценных рейдах.
Для некоторых людей это может быть непривычно. Если вы захотите, вы сможете отправлять все сообщения в файл, но мы не рекомендуем так делать, потому что это нарушает концепции мобильности. Ведь для того, чтобы посмотреть ошибки, вам нужно будет заходить на сервер и получать нужный файл, что не всегда можно сделать. В любом случае выбор за вами.
Иногда при дебаге или для тестирования устройств, необходимо отправить что-то во входящий порт (вызвать событие устройства). Это очень простой способ быстрого тестирования реакции на входящие данные. Для этого можно воспользоваться вкладкой "Порты", в разделе "вызов входа" выбрать нужный и нажать кнопку "В консоль".
VRack2 Manager устроен так, что когда вы заходите в разделы по типу портов, метрик, экшенов, данных - происходит сброс интерфейса, что не очень удобно. Поэтому всегда есть скрытая консоль, в которой сброса не происходит. Кнопка консоли всегда доступна справа вверху интерфейса - откроем ее:

Во вкладке порты виден наш добавленный в консоль порт. В тело запроса можно отправить любое значение, которое может быть представленно в виде JS выражения. Например, 100+100 или {value: 100} и тп.
С захватом порта похожая ситуация. Заходим в порты, в разделе "захват выхода" - выбираем порт и добавляем в консоль. При переходе в консоль нажимаем кнопку плей и ждем, когда пройдет информация.
Пример успешного захваченного значения:

Ручное управление портами может показаться мелочным функционалом. Но факт обмена сообщениями между устройствами уже может много сказать при дебагинге. А отправка значения в порт помогает быстро протестировать часть функционала.
Экшены - это методы устройства, которые можно вызвать через WebSocket API - например опять же из VRack2 Manager. Вкладка экшены появляется, только если экшены были зарегистрированны самим устройством.

Надпись в красной рамке, нам как бы намекает, что лучше воспользоваться консолью, но в данном случае мы отправили экшен прямо с этой страницы.
При добавлении экшена, вы выставляете к нему требования по данным. Если данные не соответствуют требованиям, то VRack2 отобьет ошибкой. Тут же, кстати, можно увидеть и ошибку, в случае если что-то пошло не так:

В VRack2 встроена небольшая inMemory база данных - VRackDB. Она НЕ хранит данные на диске, а достаточно эффективно хранит данные в памяти, я уже когда-то писал о ней.
Так вот теперь она встроена прямо в VRack2. Устройства могут регистрировать свои собственные метрики, для которых потом можно сформировать графики.
Выглядеть это может как-то так:

Это база не для хранения супер-научных данных. В первую очередь, она предназначена для оценки работы. Например, для оценки задержки опроса устройств, которые находятся на одной шине RS485:

Можно выбрать несколько метрик одного устройства и добавить их в консоль, что может упростить отображение с очень разными числовыми характеристиками:

Для отправки метрики внутри устройства нет ничего сложного - простой вызов this.metric('id', 123.45).
Давайте ненадолго забудем про абстракции, устройства, сервис файлы и тп. Посмотрим просто по факту, что вам может дать VRack2 прямо сейчас.
Достаточно поставить VRack2 и VRack2 Manager и создать 2 файла. Теперь в очень простом виде, вы уже можете писать свой сервис с онлайн мониторингом, с возможностью онлайн ивентинга, простых метрик и возможностью удаленно вызвать метод вашего класса сервиса.
Даже если мы уходим от концепций, которые продвигаются внутри VRack2, вы все равно можете получить дешевый инструмент для прототипирования сервисов, тестирования, экспериментов и обучения.
К примеру, у меня к Raspberry Pi подключен датчик температуры/давления/влажности - BME280. Написав небольшую библиотечку, я хочу ее протестировать на длительный срок, или просто хочу периодически смотреть динамику значений.
Вот такой код мне поможет это сделать:
const { Device, Metric, Rule } = require("vrack2-core"); const i2cBME280 = require("./i2cBME280") class BME280 extends Device { // Определяем настройки, которые мы получаем из сервис файла checkOptions() { return { busNumber: Rule.number().integer().default(22).min(0).description('Идентификатор шины'), address: Rule.number().integer().default(0x76).min(0x76).max(0x77).description('адрес датчика'), interval: Rule.number().integer().default(1000).min(1000).description('Частота опроса') }; } // Определяем метрики metrics() { return { temperature: Metric.inS().retentions('1s:5m, 5s:30m, 1m:1d').description('Темп. °C'), pressure: Metric.inS().retentions('1s:5m, 5s:30m, 1m:1d').description('Дав. гПа'), humidity: Metric.inS().retentions('1s:5m, 5s:30m, 1m:1d').description('Влаж. %') }; } // Это наш дисплей shares = { initted: false, fail: 0, temperature: null, pressure: null, humidity: null, }; // processPromise() запускается при старте устройства async processPromise() { // Создаем экземпляр нашей библиотеки для датчика this.sensor = new i2cBME280(this.options.busNumber, this.options.address) try { // Попытка инициализации this.sensor.init() // Если успешно ставим флаг, отправляем результат this.shares.initted = true this.render() // Начинаем опрос раз в this.options.interval мс setInterval(this.updateSensor.bind(this), this.options.interval) } catch (err) { this.error('Error init sensor, retry 5 sec', err); setTimeout(this.processPromise.bind(this), 5000) } } /** * Будет вызываться каждый this.options.interval мс */ async updateSensor() { try { // Опрос сенсора - вернет { temperature, pressure, humidity} const res = await this.sensor.readSensor() for (const n in res) { this.shares[n] = res[n] // Меняем данные на дисплее this.metric(n, res[n]) // Отправляем метрики } this.render() // Обновляем дисплей } catch (err) { this.error('Update sensor error', err); this.shares.fail++ } } } module.exports = BME280;
Написав небольшой сервис файл, который содержит актуальные настройки, что-то типа:
{ "devices": [ { "id": "BME1", "type": "vrack2-mods.BME280", "options": { "busNumber": 2 } } ] }
Запустив сервис, и VRack2 Manager - можно уже наслаждаться нашими графиками:

Причем, если что-то пойдет не так, можно подписаться на канал error устройства и прочитать какую ошибку мы получаем.
Когда-то я мог только мечтать о таком простом, легком и дешевом инструменте. И пришла пора рассказать, как его можно использовать и как он уже используется сейчас.
Начнем от простого и пойдем к сложному.
Учитывайте, что я буду перечислять реальные проекты и реальные сервисы. Это не значит, что другие вещи будет реализовать сложно или невозможно. В первую очередь хочется показать именно практическое успешное применение.
Самые простые сервисы обычно состоят из одного устройства. Скажу честно - у меня не сильно много таких. В основном это:
сервера статики
мелкие закладки для ручного запуска
генераторы конфигураций
удалятели ненужных файлов
сетевые, типа UDPSplitter, который принимает Lora данные и отправляет их на 2 разных сервера.
Это все заплатки, без которых никак. Архитектурные исправления этих проблем будут стоить дорого по сравнению с такими решениями. Но в этом и прелесть VRack - вы можете систематизировать подобные сервисы, сложить в одном месте, красиво оформить и сгруппировать по назначению.
Таких сервисов уже куда больше и они делают уже куда более интересные вещи. В основном это информаторы, которые принимают информацию и реагируют на нее.
Примеры таких сервисов:
Алерт менеджеры
SNMP траперы
Сбор кастомных метрик и отправка их в БД для анализа
Мелкие сервисы бекапа и удаления лишних данных
Маршрутизация звонков с интеграцией в ЦРМ
На самом деле таких сервисов довольно много, часть из них создают абстракции для других API. Или, например, занимаются синхронизацией информации между двумя базами. В общем, применений тут уже очень много.
У меня даже есть простой сервис, который парсит веб-страницы в некоммерческих целях. Такие вещи тоже очень хорошо укладываются в концепцию VRack2.
Вот его схема:

Pool загружает список страниц и сверяет, что уже было загружено. Если страница не была загружена - скидывает ее в PoolCollector.
PoolCollector Загружает данные по странице и скидывает в Downloader список файлов, которые нужно загрузить.
Все работают независимо, каждый занимается своим делом.
Поскольку у нас есть возможность получать с устройств информацию в онлайн режиме и управлять ими - логично это делать из Web интерфейса.
Вот такие сервисы уже куда интереснее. Это у нас алерт панели для диспетчеров или простой интерфейс для оперативного внесения изменений в настройки, для инфраструктуры. Мониторинг очередей и состояний.
Поскольку это сервис, а не просто запускаемый скрипт - устройства могут хранить состояние. Например, можно в онлайне наблюдать за тем, кто кому в данный момент звонит, кто с кем разговариват, получая информацию с Asterisk. Да, с Asterisk вы можете получать только изменения состояния звонков, но внутри устройства хранить их текущее состояние и оформлять их как онлайн данные.
Расскажу про пример простого, но полезного сервиса. Его задача простая - объединять камеры в группы и управлять ими (включение/выключение групп камер), используя Trassir API.
Его схема:

У трассира есть особенность, у него как бы 2 разных API для разных целей - стриминга и получения структурной информации. Отсюда и такое разделение на 2 разных устройства.
В настройках можно выбрать режим настройки, в котором можно создавать группы и добавлять туда камеры. А в режиме управления все очень просто:

Не буду комментировать зачем это надо, людям надо - мы сделали. Естественно можно глянуть картинку с камер, но мы этого сейчас делать не будем.
Надо понимать, что большинство таких сервисов - чисто технические. В основном, чтобы работяги могли получать информацию в онлайн режиме. Заявки, алерты, техническая информация.
Это уже слой, где VRack сложно найти конкурентов по цене производства. Он слишком хорошо справляется с такого рода автоматизацей.
Например, у нас был сделан интерфейс для быстрого просмотра и редактирования уставок мониторинга:

Вам звонят, говорят бла бла бла, у нас тут на постоянку температуру подняли - мы просто заходим в интерфейс на мобилке, жмем 2 кнопки и вуаля - диспетчеры спят спокойно.
Подобные интерфейсы всегда стараюсь делать для мобилки, чтобы всегда иметь возможность решить проблему или дать такую возможность людям (телефон с браузером практически у всех есть).
Поскольку интерфейс у нас обновляется в онлайн режиме - нам достаточно просто организовывать всякие интерактивности на стримах. Лично для себя я делал отображение текущего трека, который подтягивался из Subsonic. Он менялся в онлайне на трансляции с приятной анимацией.
Еще писал сервис, который отображал на экране текущую игру и мои личные оценки по трем критериям. А заполнялась эта информация из отдельного интерфейса:
Настройки конечно выглядят очень технически:

Сам уже не помню как это делал. В настройках кстати можно искать игру в RAWG и устанавливать ее активной на стриме:

На самом же стриме - добавляются специальные веб странички, на которых сверстана нужная информация:

Причем, если на странице настроек нажать любую управляющую клавишу, например hide/show - на стриме это будет отражено моментально. Или, например, если нажать "Установить" на другую игру - это моментально отобразится.
Поскольку VRack может в асинхронность, API и т.п. развлечения, не сложно будет накидать, например, интеграцию с чатом и т.п. функционал. Думаю, что для коммерческих стримов это бы очень хорошо подошло.
Кстати, это можно назвать примером простого сервиса - вот его схема:

Как видите, даже без связей можно делать вполне себе полноценные полезные сервисы.
Недавно зашел в одну из всем известных пиццерий. Сделал там заказ и наблюдал за очень печальной картиной. Табло, которое отображает текущие заказы - выдавало буквально меньше кадра в секунду. Видно было как тяжело это все рендерилось, на фоне еще были снежинки, которые просто телепортировались раз в ~2 секунды.
Все бы ничего, но вроде как эта контора когда-то хвасталась, что они набрали чуть ли не под сотню? айтишников себе в штат, точно не помню, но помню, что для такой конторы цифра была точно впечатляющая. Ну после этого, конечно, их цены прилично так взлетели, ну да не суть.
Грустно наблюдать, когда ты видишь задачи для VRack2, которые он выполнит в 1000 раз лучше.
В VRack2 можно легко делать всякие табло для касс с онлайн отображением. Ну знаете - когда пикнули товар, а он сразу отобразился на экране. Всякие системы онлайн заказов, когда человек приходит, выбирает что ему нужно и все сразу моментально улетает исполнителям.
Такие вещи в основном работают на событиях. Создать заказ, оплатить заказ, отправить его готовиться, поставить статус "готовится", приготовить и поставить статус - "готов". Чтобы человек все это видел прямо в онлайне, оперативно и мобильно.
Причем организовывать такие вещи на VRack2 ну очень дешево. Используя Vue3 для интерфейса можно сделать все с анимациями, по красоте, и чтобы это выдавало явно не 1 кадр в 2 секунды.
У нас на том же принципе работают, например, алерт панели и другие информационные "табло". Прелесть VRack2 тут в том, что если диспетчер нажимает у себя в интерфейсе кнопку - это изменение видят сразу все, кто подключен к этому же интерфейсу. То есть можно открыть несколько браузеров на разных компьютерах с одним интерфейсом и он автоматически будет синхронизироваться.
Еще в таких случаях может быть 2 интерфейса, один для общего отображения, другой с управлением для обслуживания.
Если вам интересна эта тема, очень рекомендую попробовать VRack2. Реализовать в очень простом виде и оценить насколько вам это подходит.
В конце статьи есть ссылки на учебные примеры для интерфейсов.
Расскажу и о примере тяжелого проекта. Так получилось, что подписался на него специально, чтобы протестировать, насколько VRack может хорошо адаптироваться к проекту. Это такой своеобразный тест на мобильность.
Суть его в том, что он обслуживает окружение для запуска инстансов 1С внутри Linux.
Он занимается очень разными делами:
Создание/обновление/удаление конфигураций для корректного запуска инстанса
Управление доступом для пользователей
Управление личными директориями пользователей
Управление RDP
Обновление баз данных
Обслуживание очередей задач
На самом деле очень-очень много чего. Самое важное в нем - при всем своем объеме, он не имеет внешних npm зависимостей. Это сделано намеренно. Мне не хочется отвечать за чужой код в таком проекте.
Вот зашакаленная схема этого сервиса, просто для оценки объема:

Это не просто один сервис где-то на одном сервере - VRack работает на множестве серверов.

Каждая строчка - отдельный физический сервер. И все это уже давно работает без меня. Они сами все деплоят, сами настраивают, меня не привлекают.
На сводной странице мониторинга отображаются статусы, наличие ошибок, загруженность серверов, загруженность дисков, текущая очередь. На самом деле информации куда больше, но появится она только в определенных условиях.
Все обновление данных происходит, опять же, в онлайне. А занимается отправкой всей информации на самом деле второй сервис, который расположен рядом с основным - большим сервисом.
Сделано это не просто так. Если мы сделаем отправку подобной информации из основного сервиса и он упадет - то ничего не отправится. Поэтому используется другая схема.
Есть один большой сервис, который выполняет всю работу, и есть другой - маленький сервис, который следит за большим и сообщает обо всем на сервер мониторинга. Если большой сервис упадет - на сервере мониторинга это отобразится и прямо там можно будет посмотреть ошибку.
Еще одна особенность VRack в том, что он может создавать прозрачные связи между устройствами, которые работают в разных сервисах. Поэтому основной - большой сервис, просто передает нужную информацию в маленький сервис, а тот, в свою очередь, передает ее на сервер мониторинга.
Можно провалиться внутрь каждого сервера и посмотреть все события сервиса. Это мегаудобно, потому что позволяет искать, фильтровать и т.п. События хранятся в ClickHouse.
К сожалению, скриншот сложно будет сделать, потому что там по факту будет все замазано. Но мы можем глянуть локальную версию:

Интересная ситуация на скрине - ошибка о том, что он не смог записать в базу данных сообщение, при том что данные берутся из базы данных.
Хотелось бы просто рассказать о некоторых особенностях реализации.
Начнем с ивентов. Если, к примеру, у вас есть скрипт, который просто выполняется, что будет, если он не сможет записать событие в базу? Ну наверное проигнорит и пойдет дальше своими делами заниматься.
В VRack такие вещи можно делать совсем по-другому. Например, можно использовать Buffer. Это универсальное устройство, которое хранит объекты, пока их кто-нибудь не заберет. Типичная схема выглядит так:

Вот как это работает. Буфер получает объекты через порт entity. Устройство, которое, например, отправляет объекты в базу, запрашивает их из буфера через порт slice, отправляя число (например 100). Буфер выдает на выход первые 100 объектов. Если запись в базу прошла успешно - в порт shift отправляется количество записанных объектов. Это говорит буферу, что можно первые 100 записей удалять. Если же запись в базу прошла с ошибкой, например база не доступна, в буфере далее будут накапливаться данные, а устройство записи продолжит попытки подключения/записи.
Поэтому, получилось так, что VRack запустился раньше Clickhouse, попытался туда записать данные, - но не успешно. Потом, когда Clickhouse стал доступен, он записал туда все ивенты - вместе с ошибками попыток записи.
Это можно использовать очень много где. Например, при передаче объектов по сети. При передаче тревожных сообщений или другой информации.
И что хорошо, мы видим как оно работает. То есть нам на схеме уже понятно, где используется отложенная отправка.
Если, к примеру, информация, которая приходит в буфер, супер критически важная, можно заменить его на буфер, который будет хранить данные локально в файле с резервацией еще где-то. То есть мы можем менять поведения хранения без изменения вставлятеля или источника информации.
Расскажу еще про отслеживание инстансов.

Одна из прелестных вещей в NodeJS - это очень простая обработка событий изменения директории. В этом сервисе это используется, например, для того, чтобы отслеживать директорию с пид-файлами. Как только там происходит изменение, мы сразу же реагируем на него и в онлайне отображаем, что, например, инстанс был выключен или включен. Это магия онлайна, когда вы точно знаете что сейчас произошло и какие состояния сейчас в системе. Но отображение - это ладно. Что если инстанс завершил свою работу, когда мы его не просили? Мы можем перезапустить его. Такие вещи в VRack2 делаются очень удобно.
Еще мне нравится как тут работает очередь задач. Она запускает только определенное количество определенного типа задач. Если что-то пошло не так и задача долго выполняется - приходит сообщение в телеграм. В таком случае человек уже в ручном виде будет смотреть и следить за тем, что там и как выполнялось.
Оказалось, из-за того, что все выполняется слегка нелинейно, порой сложно отслеживать что и когда выполнялось. Для этого пришлось ввести номер сессии.

Теперь когда кто-то хочет посмотреть цепочку выполнений конкретного события в той последовательности, в которой она выполнялась - можно просто жмакнуть на номер сессии. Интерфейс автоматически отсортирует это все в нужном порядке и отфильтрует. До этого проекта я не задумывался о том, что асинхронный код так не очевидно отслеживать. Но важно и то, что VRack систематически с этим справился и решил эту задачу.
Вообще, в этом проекте есть много глобальных таймеров. Например, при выполнении одной задачи, если в определенной директории определенный файл не будет меняться долгое время - выполнение задачи прекратится с уведомлением в телеграм.
Еще по объему серверов видно, что вопрос установки и настройки сервиса прошел определенные этапы систематизации. То есть основные проблемы деплоя уже решены.
Вот тут то VRack раскрывает себя полностью. Считайте, что до этого ничего не было, вот только сейчас все началось.
Начну как всегда с простого, и пойдем к более сложным и концептуальным вещам.
У нас есть на домах IOT сборщики для данных со счетчиков, которые работают по радиоканалу. Не совсем удобно опрашивать каждый, в надежде получить последние данные по конкретному счетчику. В VRack у нас для каждого дома есть агрегатор, который собирает таблицы со всех подключенных IOT устройств. Приложение, которое занимается сбором данных, используя простой JSON запрос, забирает актуальные данные по нужному ей счетчику с самого агрегатора, не думая о том, есть ли на агрегаторе тот или иной счетчик.

То есть он полностью абстрагирует работу с реальными устройствами для сборщика данных по счетчикам. Мы можем добавить сколько угодно IOT устройств, которые будут опрашиваться асинхронно-одновременно и собирать таблицы.
Это, кстати, хороший пример того, как VRack может стать мобильной прослойкой для вашего удобства. Но такие проекты просто прозрачно приносят пользу и их не потрогать.
Часто бывает нужно простое управление конкретным устройством, например - управление вытяжкой в гостинице.
Вот как выглядит интерфейс для него:

Получилось так, что в гостиницу вытяжку поставили, а пульт к ней потеряли, а случилось это еще ого-го когда. Мне пришлось найти контору-производителя контроллера, который там стоит, и запросить у них документацию на протокол Modbus. И знаете что? несмотря на то, что это европейский производитель, они максимально, по моему мнению, помогли мне справиться с этой проблемой и выслали мне файл протокола с минимальным описанием функций. Этого было достаточно, чтобы сделать управление основными нужными функциями.
Кстати, недавно у них была проблема с двигателем и мое приложение показывало красный флаг "Авария вентиляторов". Сейчас уже все починили и все в порядке. А я то сделал эти флаги на всякий случай, оказалось работает, еще и сразу понятно стало, что там сломалось - приятно.
Управление одним устройством это типичная задача. К примеру, вы хотите собрать блок умных розеток или получать, например, данные с электросчетчика. Таких проектов мы делали много и со всеми VRack, естественно, отлично справляется.
Умный дом это уже управление несколькими устройствами. Вообще, для умного дома есть другие решения, но поскольку это тоже локальная автоматизация - мы таким тоже занимались.
Точнее мы делали управление за пределами дома: освещение, управление обогревом, мониторинг и т.п.
Для него недавно обновил интерфейс, сделал красивее:

Внутрянка там тоже неплохо выглядит - нетипично для меня:

Просто для объема - схема сервиса:

Это хороший пример как вы можете создавать виртуальные, сложные, сильные устройства, которые могут взаимодействовать с реальными устройствами.
Раньше там работало аппаратное астрореле, которое на самом деле было не особо удобное. Вместо него я написал виртуальное, которое позволяет настраивать индивидуально все для каждого выхода:

Причем, если посмотреть на схеме, то будет видно, какими выходами назначено управление AstroRelay.
Умный дом на VRack2 можно делать, если вы хотите прям полный контроль над тем, что вы делаете. Когда вы хотите внедрять какие-то прям сложные алгоритмы или, например, использовать мелкие нейросети.
В противном случае, если вы хотите, чтобы просто добавил умную лампочку и она сразу заработала без кода - лучше VRack2 не использовать. Поэтому тот, кто мне говорил, что это что-то про умный дом, немного не разобрался в вопросе.
Разного рода проектов с управлением устройствами у нас достаточно - это парковки, диспетчеризация, локальные сборщики информации и т.п.
Самые простые из них - те, где нужно только собирать данные. Такие решения отлично подходят организациям, для которых критично поддерживать определённые условия.
Например:
Теплицы
Мониторинг микроклимата в птичниках
Контроль условий инкубации
Слежение за состоянием складов
У нас чаще всего мониторинг применяется для котельных: температура, давление - всё в онлайн-режиме с уведомлениями диспетчерам.
Схема сборщика одной котельной может выглядеть так:

Сервисный файл генерируется на основе конкретного оборудования, поэтому схемы могут сильно отличаться. Вот, например, другая реализация - с иным оборудованием, но выполняющая ту же функцию:

Внимание: тема может вызвать несогласие или задеть чувства некоторых людей
Недавно у нас появилась необходимость реализовать интересный проект - систему защиты от протечек. Она должна при обнаружении протечки немедленно перекрывать краны и уведомлять диспетчеров.
Особенность в том, что идентификация протечки должна быть адресной - у каждой квартиры может быть несколько датчиков.
Хочу разобрать особенности реализации автоматизации именно в VRack2 - на этом примере хорошо видны сильные и слабые стороны подхода.
Давайте разберёмся, где VRack2 уместен, а где нет.
VRack2 плохо подходит, если:
Контроллер должен загружаться за доли секунды.
Реакция на событие критична на уровне микросекунд (например, защита от короткого замыкания, аварийное отключение насоса при сухом ходе, реакция на концевики).
Устройство работает автономно, без ОС.
VRack2 отлично подходит, если:
Загрузка контроллера занимает 10–20 секунд - и это нормально.
Логика управления сложная, но не требует сверхбыстрой реакции (реакция в пределах 10–200 мс - более чем достаточно).
Нужна мобильность - гибко связывать датчики, исполнительные механизмы и внешние системы (Telegram, Grafana, базы данных и т.п.).
Важна скорость развёртывания: собрать рабочий прототип за пару дней, а не месяцев.
Требуется более сложная интеграция, мобильность, генерация, мониторинг, интерфейсы.
Практика показывает: лучше всего работает связка - простые локальные контроллеры/датчики (быстрые, надёжные, с минимальной логикой) + VRack2 как управляющий центр.
На примере того же шлагбаума. У него есть свой личный простой контроллер, который следит за концевиками, петлями и важными для него параметрами. Управлять же им мы можем по RS485, получая статусы и отправляя команды.
Понимаю - пристал со своим шлагбаумом - давайте приведу другой пример. Как то мы реализовывали СКУД на контроллере Iron Logic Z-5R WEB. Это вобще прекрасный контроллер. К нему подключается замок двери и считыватели карт. Когда человек прикладывает карту - он запрашивает HTTP запросом, передавая данные карты, направление, время и т.п. Если вы разрешаете - он пропускает, если же запрещаете - отбивает.
Учет карт и журналы велись в MySQL, а VRack занимался тем, что в онлайн режиме обрабатывал запросы, заполнял журналы и обрабатывал дополнительную логику. Например, если кто-то заходил в офис в неустановленное время - VRack брал фото с камер и отправлял информацию в телеграм-канал для начальства.
Так мы получаем и скорость реакции, и гибкость управления - без попыток «засунуть всё в одно устройство».
Сначала мы остановились на ПР200 - программируемом реле от ОВЕН.
Датчиков будет много, поэтому решили завести их через внешние DI-модули. ПР200 будет опрашивать эти модули и управлять выходами - либо своими, либо через отдельный DO-модуль.
Вода перекрывается по стоякам: сразу и холодная, и горячая.
Схема получается примерно такая:

Слишком много вопросов, которые как бы решаемы, но на деле - совершенно не нужны.
Тогда мне в голову пришла идея: а что если сделать контроллер самому? Было бы здорово собрать такое устройство, которое можно просто поставить - и забыть. Надёжное, простое, «на века».
И тут так получилось, что я поехал к ребятам, которые тоже занимаются автоматизацией. У них есть тоже задача - и они уже «решили» её своим способом: взяли STM32 и собрали нечто вроде ПЛК, но под свои нужды.
Начал задавать вопросы - выяснилось, что разрабатывают его уже два года. Сейчас как раз настраивают новую точку. И оказывается IP-адрес нужно прописывать вручную, потому что DHCP не реализован.
На вопрос «почему так?» ответ был примерно такой: "Да это легко сделать… просто надо заняться".
И тут меня накрыло флешбеками о том, что такое разработка собственных устройств.
У меня есть опыт - и железа, и прошивок, и отладки таких систем. Я знаю, о чём говорю.
С одной стороны - да, это интересно, даже увлекательно.
С другой - это месяцы, а то и годы:
Первая ревизия платы - пилим первую прошивку.
Вторая ревизия платы - опять пилим прошивку.
Третья - зависания.
Четвёртая - условия изменились, а требования поменялись…
А потом ещё:
Пайка партии
Тестирование в полевых условиях,
Поиск странного бага, который проявляется раз в неделю
А поскольку у МК нет возможности создавать нормальные журналы логирования - пердолинг с дебагингом вам гарантирован.
Естественно, мы говорим не про команду профессиональных ембеддед разработчиков, а про разработку в соло/дуо.
Сколько времени уйдёт у меня, чтобы довести своё устройство до рабочего состояния? Год? Два? Это при том, что тут еще не описана куча мелочей, на которые уходит просто тонны времени. Типа заказ деталей, тестирование, пайка, корпусы и т.п.
Ребятам - спасибо. Их «поделие» моментально вернуло меня в трезвое состояние.
Стало очевидно: их задачу можно было закрыть на VRack2 за две недели. (Хотя, честно - они пытались сначала на C# + Windows, но провалились. Неверно был выбран инструмент)
Тогда мы пошли путём VRack2.
Для начала накидали схему:

С модулями ввода-вывода всё просто - берём те, что подходят по количеству портов. А вот с «мини-ПК» пришлось подумать.
Мне нравится пробовать новые платформы, и недавно на рынке появился Orange Pi RV2 - одноплатник на RISC-V. Главное его преимущество - слот M.2 NVMe при цене около 5к рублей (до кризиса памяти). Это значит, что можно загружаться не с microSD, а с SSD - надёжно и быстро.
Конечно, если вам критична "железная" промышленная надёжность - можно взять и дороже - тот же Lenovo ThinkCentre IoT за 50к рублей. Но даже в этом случае выгоднее переплатить за железо, чем за разработку.
Можете посчитать сами сколько обойдется:
Зарплата embedded-разработчику, плюс стоимость изготовления и отладки плат
Или индивидуальная прошивка ПР200 для каждого дома + сама ПР200 + отладка
И еще в обоих случаях - разработка приложения для получения данных с этих устройств.
Но самое главное вы заплатите кучу своего времени, при сомнительном результате.
Всё это обойдётся значительно дороже.
Может показаться, что я против разработки собственных контроллеров, но это не так. Как уже писал выше, мы часто используем простые локальные контроллеры, которые хорошо выполняют свою простую логику. На самом деле VRack2 - это просто еще один слой абстракции. Когда разрабатывается устройство на контроллерах, там на самом деле используют похожую схему - контроллер собирает данные с локальных датчиков, используя разные шины и протоколы, например I2C SPI UART, и реагирует на это. VRack2 делает тоже самое, только на уровне выше, ему уже доступны более сложные технологии, он уже может использовать Ethernet, Wifi, SSL, WebSocket т.п. Просто люди хотят запихнуть в устройство одного уровня задачи другого уровня, а потом пытаются это все дело превозмогая решать.
Отличнейший пример - современный 3D принтер. Компьютер типа Raspberry Pi очевидно не подходит для прямого управления двигателями и экструдером для печати. Для этого используется специальный контроллер, который может точно позиционировать двигатели и точно управлять экструзией. Но вот, чтобы добавить работу с моделями, дисплеем, интеграционными возможностями, нам поможет уже микрокомпьютер по-взрослее, который может работать полноценно по Wi-Fi, поддерживать связь с облаком и т.п.
Кстати, используя VRack2, получился бы неплохой сервис для 3D печати, станков и подобных вещей.
Для связи с устройствами по RS-485 мы давно используем преобразователи USB → 4×RS-485 от Waveshare. Честно говоря, Waveshare делают очень качественные продукты за свои деньги - схемотехника продумана, работает стабильно. Для задач средней автоматизации - отличный и дешевый выбор.
А получать доступ к этим портам мы будем через VGranite - простой сервис, написанный на VRack2 Core. Он позволяет пробрасывать локальные serial-порты (COM) через Ethernet, так что RS-485 шины становятся доступны напрямую из VRack2, без костылей.
Когда мы шарим RS-485 по Ethernet - это позволяет не просто получить доступ из VRack2 - это позволяет заниматься разработкой, находясь за много-много км от самого железа. Именно так обычно и работаю. Вначале мы шарим шины, после чего я начинаю разработку на сервере, который находится за ~1700км от объекта. После того как мы все протестируем, мы уже тогда только ставим локальный контроллер с нужным сервисом. Конечно, все это происходит с прозрачным пробросом наших локальных сетей, чтобы нам приятно было с этим работать.
Железная реализация одного подъезда (извиняюсь за качество фото):

Внешне шкаф выглядит очень просто:

Логика тут такая - если лампочка горит зеленым - все ОК. Если красным - значит кран перекрыт. Кнопка под лампочкой сбрасывает состояние. Если надо перекрыть кран - можно подойти, нажать и подержать кнопку - он автоматически перекроется.
Когда железо было собрано, я занялся разработкой реализации логики на VRack2.
На первый, тестовый запуск у меня ушло всего 6 часов!
Почему так быстро? Всё дело в том, что инженер заранее подготовил документацию - и в ней была вот такая табличка:

Я взял исходник в формате CSV, преобразовал его в JSON с уже структурированными данными, типа:
{ "porch": 1, "control": "Dev::Control1", "sensor": "Dev::Sensor1", "controller": "1", "inputPort": 6, "flat": 2, "flatPrefix": "Санузел", "outputPort": 2 },
Осталось написать генератор сервис-файла - и на это ушло даже меньше времени, чем на обработку CSV. Вот что значит хорошо подготовленные исходные данные.
В результате получилась такая схема:

Впечатляющая, правда?
Потом ребята пошли по квартирам и проверили каждый датчик. "Лизнули" - закрылся нужный кран стояка.
Всё отработало идеально. Ни одной ошибки!
В этом проекте критически важно, чтобы каждое устройство работало стабильно.
Если какое-то устройство перестаёт отвечать - система автоматически создаёт алерт, который сразу летит в наш технический Telegram-канал.
И самое приятное - нам ничего для этого делать не пришлось.
За мониторинг шины RS-485 отвечает специальное устройство внутри сервиса (vrack2-net.ConverterBus). Оно следит за доступностью каждого модуля и генерирует события при ошибках связи.
Нам осталось только подписаться на эти события и отправить их в Telegram - и мы всегда знаем, если где-то что-то пошло не так.
У меня есть статистика за последний месяц работы сервиса.
Скорость. В одной RS-485 сети - 12 устройств, все работают на скорости 9600 бит/с. Каждое устройство опрашивается более двух раз в секунду.
Для нашей задачи это с запасом - нам хватило бы и одного раза секунду. Но даже если понадобится ускориться - у нас есть резерв: можно поднять скорость шины или распределить устройства по нескольким RS-485 линиям. То есть ресурс на расширение огромен.
Кстати мы всегда можем посмотреть задержки конкретного устройства:

Если какое-то устройство начнет работать некорректно - мы можем это легко диагностировать.
Надёжность. Вот статистика от устройства, которое предоставляет доступ к шине (vrack2-net.ConverterBus):

За время сбора данных было выполнено около 110 миллионов запросов - и ни одной ошибки. При этом по шине прошло полтора гигабайта данных.
Есть такие мифы, что nodejs течет как тварь, давайте глянем на потребление памяти сервисом:

Нас интересует параметр memory.heaptotal. Видно что он находится где то в районе 20МБ и никуда расти не собирается. То есть за месяц работы с памятью у нас ничего не случилось, при том, что мы молотим информацию с устройств 24/7.
Хотелось бы отметить приятные вещи в этом проекте:
Повторяемость - мне скидывают новый файлик CSV и вот через 10-15 минут дом начинает уже работать.
Мониторинг - мне легко следить за этими сервисами. Всегда можно запустить VRack2 Manager и зайти и посмотреть как работает сервис, ошибки, память, устройства. Мне не нужно для этого заходить на сервер, смотреть в консоли или писать интерфейс для мониторинга.
Есть огромный запас по ресурсам, то есть мы можем на этом же железе развернуть еще дополнительный сервис для этого дома. (на самом деле мы так и делаем)
Можно много чего еще сказать и рассказать, но сказано было и так уже много, а все так сразу и не расскажешь.
VRack2 не претендует на замену всего подряд. Но если ваша автоматизация живёт в мире событий, мониторинга, уведомлений и гибкой логики - он может стать вашим главным инструментом. И вот почему.
VRack2 распространяется под лицензией Apache 2.0 (возможно, переход на MIT). Это значает что Вы - хозяин системы, а не пользователь. Никаких скомпилированных .exe, закрытых проектов CoDeSys или ключей активации. Если программист ушел - другой пришёл, посмотрел на схему, заглянул в устройство - и продолжил работу.
VRack2 - это как медоед в мире автоматизации:
Сломался DI-модуль на RS485? Поставили Ethernet
Нужно протестировать логику до поставки железа? Заменили реальные датчики на виртуальные
Хотите добавить Telegram-уведомление? Подключили Telegram - подписали его на нужные события.
Сегодня x86, а завтра нужно переходить на Risc-V, но для вас это с технической точки зрения буквально ничего не меняет, ведь вы можете запустить VRack2 даже на телефоне.
На любое изменение или вопрос у вас всегда есть ответ
Вам становится буквально как медоеду - на все... ну вы поняли.
Раньше считалось:
Бэкапы - это для админов
Промышленка - для автоматизаторов
Умный дом - для хобби-энтузиастов
VRack2 стирает эти границы.
Потому что автоматизация - это реакция на событие.
Пришёл файл в папку - запустить бэкап
Сработал датчик воды - закрыть кран - отправить алерт
Человек нажал кнопку в интерфейсе - дверь в офис открылась
Во всех случаях вы пишете одну и ту же логику:
Подписываетесь на событие,
Выполняете действие
Отправляете результат.
И делаете это в одном стеке, с одним подходом, с одной моделью отладки. Есть единая, наблюдаемая, расширяемая система.
VRack2 очень дешев, во всех отношениях:
- Железо можно взять от 500 рублей за старый ПОС терминал
- Сам VRack2 - бесплатен
- Разработка на JS/TS - дешевле только наверное LUA? или Basic?
Но!
Клиенты перестают понимать, почему раньше за такое платили миллионы. Они не видят вашего пердолинга, не видят вашего преодолевания. Они не видят больше необходимости в дорогом железе, они буквально перестают понимать, почему под нужды какой-нибудь скады раньше приходилось брать сервера за бешеные бабки.
Так что у цены есть 2 стороны:
1. Если вы делаете все для себя - это прям супер-хорошо и выгодно. Это реально может приносить вам пользу каждый день и реально удивлять - насколько просто и хорошо это все работает
2. Если вы делаете это для кого-то:
Люди не ощущают вашего преодолевания, нет никаких дорогих лицензий, нет "дорогих" специалистов.
VRack просто работает. И люди перестают хотеть платить вам деньги.
На себе я испытал это несколько раз. Делаешь людям проект, потому что они приходят и говорят - очень надо, прям готовы платить любые бабки. А когда все работает год-два, не требуя никаких вложений, от тебя просто отказываются. Для моего бизнеса это конечно плохо, но именно так я вижу современную доступную автоматизацию.
Честно говоря, для вас альтернатив не вижу. Если ваши запросы выходят за пределы ESPHome и Home Assistant - ваш путь это VRack2.
Раньше часто видел статьи на Хабре, где люди нелепо превозмогали над простыми задачами. Читал и думал - "насколько же проще это было бы сделать на VRack".
Это касается и простых вещей - работы с разными датчиками, модулями и прочим «железом». И сложных - создания собственных станков, объединения разных программно-аппаратных продуктов.
Обычно идет привязка условной связке "Windows + нативный софт". С VRack2 можно просто сделать веб-интерфейс и управлять своими шайтан-машинами прямо с мобилки.
Я просто рекомендую вам поизучать его, посмотреть, попробовать накидать пару сервисов, накидать интерфейс к ним.
Когда писал статью про первую версию, делал акцент на том, что мне не нравится разрабатывать сам VRack, но нравится разрабатывать на нём. Сейчас ситуация немного исправилась, поскольку разработка VRack2 ведется на самом VRack2 что сильно облегчает задачу. Но дело не в этом.
Продукт на подобие VRack2 был бы классным и более массовым если бы в него вложили административный ресурс.
Например:
Если бы компании вроде ОВЕН писали сразу наборы устройств - чтобы можно было поставить и сразу работать.
Если бы был магазин/стор платных и бесплатных наборов и сервисов.
Больше обучающего материала - это очень важно.
Больше возможностей самой платформы. Хотелось бы, например, добавить быстродействующий плоттер для отслеживания быстро меняющихся данных.
Я не говорю «берите VRack2 и допиливайте его». Но если бы какая-то корпорация пошла в сторону подобных вещей - простых, доступных, прозрачных - это сильно продвинуло бы наши возможности в автоматизации.
Отсутствие систематизации в автоматизации - огромная проблема. И лично для меня VRack стал отличным решением этой проблемы. Но я бы хотел видеть подобный продукт от крупного вендора и просто использовать его, а не заниматься его разработкой, формализацией, попытками продвижения, документацией и т.п.
Ладно, что есть то есть. Давайте лучше что то интересное.
Давайте сразу определимся, все что касается первой версии VRack - можно смело игнорировать. Она, и устройства для нее лежат на gitlab. Начинать с нее будет очень сложно. Именно поэтому я практически сразу начал заниматся формализацией и написанием второй версии.
VRack2 это как Dota2, вроде и дота но не просто вторая кодовая версия.
На данный момент рекомендую пройти такой путь:
После чего, что бы понять основные концепции:
Переход к самостоятельному написанию:
Если вы хотите работать с железом:
Общие рекомендации:
В репозитории VRack2 в разделе "Разработка" вы найдете еще дополнительные темы. В разделе "Наши наборы устройств" можно посмотреть некоторые открытые устройства которые мы используем в наших работах. Там на данный момент мало устройств, по мере необходимости буду их дополнять.
Статья не ставит цели вас убедить. Это - точка. Финал моей долгой научно-практической работы.
Главное здесь-не код, а идея. Показать, что привычное-не догма. Что можно иначе.
Инструмент дешевый, доступный. Не потому что «мое», а потому что-рабочее. Я живу внутри этой системы годами. Знаю её вес. И знаю-она выдержит и чужие задачи.
Это не призыв. Это свидетельство.
Если есть интерес - пишите в комментариях. Я не против организоваться например в некомерческой группе в телеграм - помогать людям, и дальше развивать проект.
В последние пол года было потрачено много сил на формализацию, исправление проблем, документацию и тп. От чего есть определенная усталость. Если будет интерес, появяться и новые силы.
Автор котиков - Я. Художница - Vyalique - ей большое спасибо за работу.