Как мы «взломали» MasterSCADA4D: выкинули стандартные блоки и заставили SCADA работать на SVG

от автора

Приточная установка на собственной библиотеке в MasterSCADA4D

Приточная установка на собственной библиотеке в MasterSCADA4D

Если вы хоть раз разрабатывали SCADA-интерфейс, то знаете эту боль: унылые стандартные элементы, примитивная графика, дизайн уровня 90-х и никаких особо альтернатив, кроме как использовать свои изображения .png, а в качестве «анимации» использовать скрытие и отображение кучи картинок друг над другом.

Мы решили разработать свою библиотеку элементов для ОВиК. Взяли и «взломали» систему: наняли дизайнеров, отрисовали всё в Figme в SVG, а потом научили эти картинки анимироваться и управляться как родные блоки.

Что не так со стандартными элементами

Стандартные блоки в MasterSCADA4D вполне информативны, но не особо функциональны. Их набор довольно скуден и не гибок. Нет возможности легко адаптировать интерфейс к темной и светлой темам, скрыть ненужные элементы в объекте.

Стандартные элементы ОВиК

Стандартные элементы ОВиК

Мы сделали довольно много объектов и довольно часто слышали просьбы служб эксплуатации изменить стандартное, добавить темную тему, возможность кастомизации, в том числе цветовой.

Приточная установка с резервирование двигателей в MasterSCADA4D

Приточная установка с резервирование двигателей в MasterSCADA4D

Любое нестандартное оборудование, или элементы установки приходилось делать изображениями. Создавали несколько картинок с разным фоном \ цветом индикаторов: в режиме работа, останова, аварии. Затем скрывали ненужные через переменные, описывая в программе на ST логику отображения нужного режима. И так каждый раз. Проблема еще заключалась в том, что в таком решении кастомные объекты были непохожи на стандартные: другой стиль, нет анимации, нет возможности смены цвета (либо снова делать все через множество картинок с поочередным отображением, что при «анимации» давало «рваный» эффект)

«Взлом» стандартных элементов SCADA

Когда решили создать свою библиотеку устройств, в справке на SCADA довольно поверхностно было описано как это работает, как именно привязать управление или анимацию к элементу, какие поддерживаются эффекты и примеры их реализации.

Через техническую поддержку мы запросили исходники пары стандартных устройств и принялись ковырять их код.

Суть следующая: каждый элемент имеет изображение в формате .svg, в котором все его его отрисованные элементы сгруппированы по функциональному назначению (например, по режимам работы) и написан код работы с ними, и файл .xml, в котором описываются все внешние параметры, которые будут управлять элементами в объекте.

Пример группировки элементов в Inkscape

Пример группировки элементов в Inkscape

Пример кода в файле .svg (достаточно открыть файл текстовым редактором)

<defs     id="defs1" />  <style     type="text/css"     id="style1"><![CDATA[ #pump.Alarm #power_off{display:none}  #pump.Alarm #power_on{display:none} #pump.Alarm #mode_visible{display:none} #pump.Alarm #alarm_pmp_on{display:inline}  #pump.AlarmSensor #temp_visible{display:none} #pump.AlarmSensor #alarm_temp_on{display:inline}  #pump.Start #power_off{display:none}  #pump.Start #power_on{display:inline} #pump.no #temp_visible{display:none}  #pump.noFC #power_visible{display:none} #pump.noFC #power_invisible{display:inline} #pump.noFC #mode_visible{display:none}   ]]></style>

А в файле .xml с таким же названием, что и изображение в .svg указываем используемые параметры

<?xml version="1.0" encoding="utf-8"?><SvgDef xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" CreateCommonAvary="false">  <ParameterDefs>    <ParameterDef Name="Rotation" DisplayName="Вращение" Type="STRING" ParamType="Attribute" ItemId="pump" Path="class">      <Value DisplayName="Выкл">Stop</Value>      <Value DisplayName="Вкл">Start</Value>    </ParameterDef>    <ParameterDef Name="Alarm" DisplayName="Авария" Type="STRING" ParamType="Attribute" ItemId="pump" Path="class">      <Value DisplayName="Выкл">noAlarm</Value>      <Value DisplayName="Вкл">Alarm</Value>    </ParameterDef>    <ParameterDef Name="AlarmSensor" DisplayName="Авария датчика" Type="STRING" ParamType="Attribute" ItemId="pump" Path="class">      <Value DisplayName="Выкл">noAlarmSensor</Value>      <Value DisplayName="Вкл">AlarmSensor</Value>    </ParameterDef>    <ParameterDef Name="Invis" DisplayName="Наличие датчика" Type="STRING" ParamType="Attribute" ItemId="pump" Path="class">      <Value DisplayName="Нет">no</Value>      <Value DisplayName="Да">yes</Value>    </ParameterDef>    <ParameterDef Name="InvisFC" DisplayName="Наличие ПЧ" Type="STRING" ParamType="Attribute" ItemId="pump" Path="class">      <Value DisplayName="Нет">noFC</Value>      <Value DisplayName="Да">yesFC</Value>    </ParameterDef>    <ParameterDef DisplayName="Название" Type="STRING" ParamType="Attribute" ItemId="name_text" Path="content" />    <ParameterDef DisplayName="Статус" Type="STRING" ParamType="Attribute" ItemId="mode_text" Path="content" />    <ParameterDef DisplayName="Мощность" Type="STRING" ParamType="Attribute" ItemId="power_text" Path="content" />    <ParameterDef DisplayName="Размерность мощности" Type="STRING" ParamType="Attribute" ItemId="power_postfix_text" Path="content" />    <ParameterDef DisplayName="Значение датчика" Type="STRING" ParamType="Attribute" ItemId="temp_text" Path="content" />    <ParameterDef DisplayName="Размерность датчика" Type="STRING" ParamType="Attribute" ItemId="temp_postfix_text" Path="content" />    <ParameterDef Name="StateWorkColorOn" DisplayName="Цвет состояния Вкл" Type="HMI.SolidColorType" ParamType="Attribute" ItemId="circle2_on" Path="stroke" />    <ParameterDef Name="StateWorkColorOff" DisplayName="Цвет состояния Выкл" Type="HMI.SolidColorType" ParamType="Attribute" ItemId="circle2_off" Path="stroke" />  </ParameterDefs></SvgDef>

Как на самом деле работает «взлом»: разбор на живом примере насоса

Возьмем за основу реальный файл насоса, который мы сделали для своей библиотеки. В нем есть:

  • индикация работы/останова с анимированным вращением;

  • авария (моргающая красная рамка);

  • отображение мощности в процентах (или текст «ВЫКЛ»);

  • опциональный датчик температуры;

  • два режима отображения: с частотным преобразователем (ПЧ) и без него.

Структура SVG: группировка по состояниям

Внутри файла pump.svg все элементы сгруппированы в теги <g> с понятными id:

  • power_on – вращающаяся синяя дуга (двигатель работает)

  • power_off – статичная залитая дуга (двигатель остановлен)

  • alarm_pmp_on – мигающая красная рамка и текст «АВАРИЯ»

  • power_visible / power_invisible – показывают либо число (100 %), либо слово «ВЫКЛ»

  • temp_visible / alarm_temp_on – нормальный или аварийный режим датчика

  • mode_visible – текстовый статус (например, «ВЫКЛ»)

Важное правило: в SVG нельзя просто взять и спрятать группу через display:none – это не сработает. Мы используем каскадные CSS-правила, которые написаны внутри тега <style> в начале файла.

Вот пример из кода:

#pump.Alarm #power_off{display:none} #pump.Alarm #power_on{display:none}#pump.Alarm #mode_visible{display:none}#pump.Alarm #alarm_pmp_on{display:inline}

Если у корневого элемента с id="pump" есть класс Alarm, то:

  • спрятать группу power_off

  • спрятать группу power_on

  • спрятать mode_visible

  • показать alarm_pmp_on

Таким образом, переключая класс у корневого тега <g>, мы изменяем отображение целых блоков графики, чистая магия CSS + SVG.

Как SCADA управляет этими классами

В комплекте с SVG идет XML-файл с расширением .xml. В нём описано, какие параметры из проекта MasterSCADA4D за что отвечают.

Например:

  • Name="Alarm" – имя переменной внутри SCADA, которую вы привяжете к тегу (биту аварии).

  • ItemId="pump" – какой элемент SVG мы меняем (наш корневой <g id="pump">).

  • Path="class" – мы будем изменять атрибут class этого элемента.

  • Значения: если переменная Alarm = «Выкл», класс становится noAlarm; если «Вкл» – класс становится Alarm. А в SVG уже есть правила, что делать при появлении класса Alarm (см. CSS выше).

Аналогично сделано для:

  • Rotation – переключает классы Stop / Start (вращение анимации)

  • InvisFC – переключает классы noFC / yesFC (скрывает или показывает текст «100%»)

  • AlarmSensor – отвечает за аварию датчика температуры

Анимация без скриптов

Вращение двигателя сделано через SVG-анимацию:

<animateTransform   attributeName="transform"   type="rotate"   from="0 107.44529 130.13976"   to="360 107.44529 130.13976"   dur="2s"   repeatDur="indefinite" />

Этот код вращает синюю дугу вокруг центра насоса. Анимация встроена прямо в группу power_on. Пока группа скрыта (класс Stop) – вращения нет. Как только SCADA присваивает класс Start – дуга появляется и начинает крутиться.

Аварийное мигание сделано через animate для прозрачности:

<animate   attributeName="opacity"   dur="1s"   values="0.2;0.8;0.2"   repeatCount="indefinite" />

Динамический текст и единицы измерения

В параметрах XML вы можете привязать любой текст внутри SVG:

<ParameterDef DisplayName="Мощность" Type="STRING" ParamType="Attribute" ItemId="power_text" Path="content" />

ItemId="power_text" – это идентификатор текстового элемента внутри SVG.
Path="content" – значит, SCADA будет заменять содержимое этого текстового узла (то, что между <text>...</text>).

Точно так же можно менять цвет обводки или заливки:

<ParameterDef Name="StateWorkColorOn" DisplayName="Цвет состояния Вкл" Type="HMI.SolidColorType" ParamType="Attribute" ItemId="circle2_on" Path="stroke" />

Это позволяет пользователю прямо в редакторе SCADA выбрать цвет работающего двигателя – без правки SVG.

Стоит учесть

  • Имена классов в CSS должны совпадать со значениями в XML (<Value DisplayName="...">Точно_такое_же_имя_класса</Value>).

  • Корневой элемент SVG (обычно <g id="myDevice">) должен иметь атрибут class, который SCADA будет менять.

  • Если вы хотите динамически менять цвет – используйте атрибуты stroke или fill, а не CSS-классы.

  • Анимации (animateanimateTransform) работают только когда группа видима. Это экономит ресурсы.

После сохранения в среде разработки MasterSCADA4D добавляем объект, создаем окно, нажимаем на окно в дереве проекта правой кнопкой и Импорт SVG, после чего появится окно предпросмотра с привязкой параметров.

Окно подтверждения импорта нового объекта из SVG

Окно подтверждения импорта нового объекта из SVG

После подтверждения можно использовать наш собственный элемент в проекте со всеми его прописанными свойствами и анимациями.

Параметры элемента в MasterSCADA4D

Параметры элемента в MasterSCADA4D

Как это собрать воедино

  1. Рисуете в Figma или Inkscape все состояния элемента, группируете их с понятными id.

  2. Открываете SVG в текстовом редакторе, добавляете блок <style> с CSS-правилами включения/выключения групп по классам.

  3. Создаёте XML с описанием параметров: для каждого переключателя (авария, работа, наличие датчика) указываете, какой id и какой атрибут (classcontentstroke) менять.

  4. В MasterSCADA4D через меню «Импорт SVG» выбираете оба файла. Среда сама подхватит параметры из XML и предложит их привязать к тегам проекта.

Ссылка на исходники собственного элемента в данном примере будет в конце статьи

Разработка собственной библиотеки элементов в MasterSCADA4D

Инженеры творят могущество, но именно художники спасают мир от топорности.

Собрались, покопались в примерах, поняли как нужно и начали искать дизайнеров. Дизайнеры знают как будет красиво, но не понимают как это оборудование работает и какую индикацию нужно отображать, поэтому совместными усилиями начали прорабатывать варианты в Figma.

Пример водяного нагревателя в Figma

Пример водяного нагревателя в Figma

Составили Техническое задание, показали на живом оборудовании как это выглядит, обсудили как это должно выглядеть и приступили к работе. Вариантов было много…

Пример парового увлажнителя в Figma

Пример парового увлажнителя в Figma

Для каждого элемента было сделано много разных вариантов.

Огромная благодарность за терпимость и понимание чутких творцов

Переключатели в Figma

Переключатели в Figma

После чего начали компоновать в установки в различных комбинациях, чтоб выяснить оптимальное расположение индикаторов и выступающих частей. (например, чтоб слева от водяного нагревателя с трубами и насосом поместился электронагреватель, не перекрывая элементы друг друга).

Наборы установок в Figma

Наборы установок в Figma
Больше фото
Проработка аварийных индикаторов

Проработка аварийных индикаторов
Отображение элементов в светлой теме

Отображение элементов в светлой теме
Аварии по всем элементам

Аварии по всем элементам
В остановленном состоянии

В остановленном состоянии
В работе

В работе
Без верхних и нижних подписей

Без верхних и нижних подписей
На разном светлом фоне

На разном светлом фоне
Подбор размеров при сложных установках

Подбор размеров при сложных установках

После довольно долгой и кропотливой работы мы доделали свою библиотеку элементов для различных систем и потихоньку запускаем на новых объектах.

Главный экран АРМ Диспетчера на одном из объектов в темной теме

Главный экран АРМ Диспетчера на одном из объектов в темной теме
Очень много скринов
Приточная установка в темной теме

Приточная установка в темной теме
Вытяжные установки в темной теме

Вытяжные установки в темной теме
Дренажные приямки

Дренажные приямки
Статусы ВРУ и анализаторы сети

Статусы ВРУ и анализаторы сети
Тепловые завесы и кондиционеры

Тепловые завесы и кондиционеры
Таблица связи с устройствами

Таблица связи с устройствами
Журнал событий

Журнал событий
Журнал активных аварий

Журнал активных аварий
Окно настроек

Окно настроек
Окно настроек в светлой теме

Окно настроек в светлой теме
Скрытие блоков у элементов

Скрытие блоков у элементов
Главное окно

Главное окно
Приточная установка

Приточная установка
Приточная установка со скрытыми подписями

Приточная установка со скрытыми подписями
Вытяжки

Вытяжки

Скачать ПРИМЕР из статьи.

Всем красивых и информативных интерфейсов, а мы пошли дальше отрисовывать ОВиК.

Telegram канал

ссылка на оригинал статьи https://habr.com/ru/articles/1040060/