惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Cisco Talos Blog
Cisco Talos Blog
V
V2EX
C
Check Point Blog
GbyAI
GbyAI
D
Docker
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
B
Blog RSS Feed
H
Hackread – Cybersecurity News, Data Breaches, AI and More
N
Netflix TechBlog - Medium
T
Troy Hunt's Blog
博客园 - Franky
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Microsoft Security Blog
Microsoft Security Blog
P
Privacy & Cybersecurity Law Blog
WordPress大学
WordPress大学
The Cloudflare Blog
S
SegmentFault 最新的问题
Latest news
Latest news
Microsoft Azure Blog
Microsoft Azure Blog
P
Proofpoint News Feed
I
InfoQ
博客园 - 【当耐特】
NISL@THU
NISL@THU
A
About on SuperTechFans
T
Tailwind CSS Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
The Hacker News
The Hacker News
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Scott Helme
Scott Helme
雷峰网
雷峰网
C
CXSECURITY Database RSS Feed - CXSecurity.com
Security Latest
Security Latest
V
Vulnerabilities – Threatpost
Security Archives - TechRepublic
Security Archives - TechRepublic
A
Arctic Wolf
Hacker News: Ask HN
Hacker News: Ask HN
N
News and Events Feed by Topic
IT之家
IT之家
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
aimingoo的专栏
aimingoo的专栏
T
Threat Research - Cisco Blogs
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
阮一峰的网络日志
阮一峰的网络日志
SecWiki News
SecWiki News
大猫的无限游戏
大猫的无限游戏
S
Security Affairs
The Register - Security
The Register - Security
www.infosecurity-magazine.com
www.infosecurity-magazine.com
L
LINUX DO - 热门话题
T
Tor Project blog

Все публикации подряд на Хабре

Ловим музу за клавиатуру: как айтишнику стать автором Что умеет Midjourney в 2026? Мой немного грустный разбор этого шикарного инструмента Никто не любит писать тесты, но ИИ может исправить это IPv8 выглядит как мечта. Поэтому почти наверняка не взлетит Производители вернули в продажу материнки с DDR3. Что происходит? Управление агентом с телефона через Telegram теперь в KodaCode От координации к лидерству: как меняется роль руководителя разработки Я сделала родителям бизнес вместо пенсии: зарабатываем 70 тысяч, мама не даёт продать В три раза быстрее приемка товара и оптимизация трудозатрат на 73%: как «РСТ-Инвент» помог Gulliver Group ИИ-шечный мир победил? О влиянии искусственного интеллекта на игропром Кремль снижает давление на Телеграмм пока Европа строит интернет по паспорту Как CEO, CTO и CIO за 8 часов собрали ИИ-директора, который умеет держать позицию под давлением Как (не) потерять домен за выходные Вместо 8 разных VPS: как я организовал практику студентам на одном сервере Почему твой Open Source проект не замечают? R&D: искусство управления неопределенностью в разработке AI-дефляция: вакансий для разработчиков больше, а рост зарплат — худший за 15 лет Мы отдали управление роботами OpenClaw. Что из этого вышло Галактический ID: система идентификации для всех форм разумной жизни Шесть основ бизнес-анализа: начинаем с вопроса «Кто в игре?» Код-ревью, в котором дело не в коде Данные переехали. Команда — нет Системной подход к сдаче OSWE в 2025 Почему комната управления реактором покрашена в цвет морской пены 4 YAML-файла вместо PySpark: как аналитикам строить пайплайны без разработчиков LLM-агент для поиска свободных доменов: автоматизируем подбор Когда, зачем и как правильно начинать новую сессию в Claude Code? Как я заставил нейросеть писать макросы для FreeCAD Анатомия ИИ‑агента для подбора персонала. От тысячи резюме к топ‑10 за минуты Опыт разработчика как экономика внимания Автономность как точка невозврата: кто будет субъектом в цифровом будущем Обучение ИИ в «диких» условиях: как рутинные действия превращаются в датасеты Как измерить LLM для задач кибербеза: обзор открытых бенчмарков Где хранить код? Сравнение GitHub, GitLab и Bitbucket Математика объясняет, почему нормальное распределение встречается повсюду Почему ваш FinOps не работает: 12 тезисов от практиков Как подписать проектную документацию УКЭП с использованием бесплатных лицензий Pilot Адаптивное администрирование Sigla Vision Я грузил уран в бочки, а потом 20 лет строил ИТ в атомной отрасли Чем позвонить с Эвереста? История и обзор спутниковой связи. Часть 2 Как языковая модель помогает контролировать качество инструктажей по охране труда в металлургии Как не передать на desktop свой IP в РКН Анатомия SAP Privileges: как устроено управление правами в macOS MoneyDev: Сказка про три главных слова Обновлённый токенизатор видео K-VAE 2.0 от Сбера Как сделать диспетчеризацию дома на 1284 квартиры почти бесплатно Как мы разогнали железную дорогу Мы дали агентам рутину. Теперь надо решить — что делать с освободившимся временем Токсичный контент, промпт-хакинг и защита ИИ — всё о Guardrails для LLM Умный город начинается с точного взгляда: как «Фалькон Тех» меняет пространство к лучшему Навайбкодил приложение для анализа графов Почему Дюну так интересно читать? Упрощаем работу с рутиной или как стать Гендальфом Белым Деконструкция Go: CPU, RAM и что там происходит. Go Assembler база. Часть 1.1 Какие профессии исчезнут из-за ИИ, а какие появятся? И что с этим делать Как мы построили IT-отдел, где хочется расти: архитектурные встречи, прозрачные метрики и книжные подарки Rufler: Делаем из Claude Code автономный рой через один YAML-конфиг Sing-box и белый список приложений Как построить надёжный обмен сообщениями в микросервисах: лучшие практики для enterprise OpenAI строит MLM-пирамиду, а McKinsey и Accenture помогают ей в этом Дом, который не построил Фишер (Часть 2) «Сверхзвуковой математик» против «Вдумчивого логиста»: битва алгоритмов 3D-упаковки Мультимодальные модели – грубый и дорогой инструмент Разговоры ничего не стоят. Код тоже Проверки физических лиц: с кого начнет ФНС Топ-10 бесплатных нейросетей для создания видео в 2026 году Первые слои кода: как наши решения сегодня определяют архитектуру ИИ на десятилетия Разработка нового статического анализатора: PVS-Studio JavaScript Поиск уязвимостей ПО: базовый минимум или роскошный максимум Почему оценка персонала не работает как инструмент управления Как мы разработали ИИ-ассистента и сократили рутину продуктовой команды на 50% Как я ушел из найма, нажарил косточек и продал на маркетплейсах на 168 млн в год Когда 1С:ERP уже внедрена, а нормального производственного плана всё ещё нет Как я сделал Claude мультимодальным, подключив к нему Qwen Omni Как приглашение на вакансию мечты превращается в атаку Infrastructure as Code: философия и лучшие практики IaC Тестируем Yandex Code Assistant на задаче, в которой нужно хранить секреты nxs-universal-chart v3.0: новое поколение универсального Helm-чарта Callback Injection: Техника, которая отправила Microsoft Defender в глухой нокаут «Все идеи на стол»: митап как способ вывести проект из тупика Сегодня я узнал нечто новое о GPU благодаря багу в своей игре Как заставить LLM ̶ ̶г̶а̶л̶л̶ю̶ ̶ эволюционировать Карта событий как фундамент аналитики: практический кейс для E-commerce Что выбрать для AI: x86, ARM или RISC-V? Дайджест железа за март Роль соматических мутаций в развитии аутоиммунных заболеваний: путь к избирательной терапии Mythos от Anthropic — тревожный сигнал для всех, а не только для банков Guardrails для LLM на Java: как приручить промпт‑инъекции и токсичные ответы Green-VLA: как мы собрали VLA-модель для реального антропоморфного робота и не потеряли обобщение Финансовая гонка вооружений: почему умные люди добровольно в ней участвуют Эра ИИ-агентов наступила: выбираем лучшего цифрового сотрудника # Практический опыт внедрения WinCC Redundancy на производственном предприятии Сделал MVP за 3 дня, а потом неделю прикручивал оплату. Оно того стоило? Физика против Маска: почему Starship V3 может оказаться ещё одной катастрофой Нефть Венесуэлы: крупнейшие запасы в мире, но не крупнейшая нефтяная держава JPA 4. Переосмысление Hibernate Почему зеркальная фотокамера Nikon D5 десятилетней давности идеально подошла для миссии «Артемида-2» Проект «Уровень-Спутник» или как мы сделали платформу для гидрологов «Замедлиться, чтобы ускориться»: почему ИИ повышает цену ошибок в требованиях и архитектуре Как с нуля поднять трафик IT-компании на 1657% при бюджете 55 тыс. и выжить Pixel-perfect Downsampling — идеальная отрисовка 50 миллионов точек без потерь
Как мы «взломали» MasterSCADA4D: выкинули стандартные блоки и заставили SCADA работать на SVG
ЦИНТРОН · 2026-05-27 · via Все публикации подряд на Хабре

Средний

8 мин

9.1K

Приточная установка на собственной библиотеке в 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

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

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

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

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

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

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

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

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

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

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

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

Проработка аварийных индикаторов

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

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

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

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

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

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

В работе

В работе

Без верхних и нижних подписей

Без верхних и нижних подписей

На разном светлом фоне

На разном светлом фоне

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

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

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

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

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

Очень много скринов
Приточная установка в темной теме

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

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

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

Дренажные приямки

Дренажные приямки

Статусы ВРУ и анализаторы сети

Статусы ВРУ и анализаторы сети

Тепловые завесы и кондиционеры

Тепловые завесы и кондиционеры

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

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

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

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

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

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

Окно настроек

Окно настроек

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

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

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

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

Главное окно

Главное окно

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

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

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

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

Вытяжки

Вытяжки

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

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

Telegram канал